@peter.naydenov/shortcuts 4.0.2 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +54 -0
- package/Changelog.md +9 -0
- package/README.md +935 -426
- package/dist/plugins/click/_listenDOM.d.ts +2 -2
- package/dist/plugins/form/_listenDOM.d.ts +4 -4
- package/dist/plugins/hover/_listenDOM.d.ts +2 -2
- package/dist/plugins/key/_listenDOM.d.ts +2 -2
- package/dist/plugins/scroll/_listenDOM.d.ts +2 -2
- package/dist/shortcuts.cjs +1 -1
- package/dist/shortcuts.esm.mjs +1 -1
- package/dist/shortcuts.umd.js +1 -1
- package/graphify-out/.graphify_benchmark.json +35 -0
- package/graphify-out/.graphify_python +1 -0
- package/graphify-out/GRAPH_REPORT.md +121 -0
- package/graphify-out/cache/024633ee076562ce0dbc0bf3b5315906f4e5d48c57bc96856b98cd5d42a69009.json +1 -0
- package/graphify-out/cache/037d2ba5552034c06beca677b1914ac7a053f696dfeaf12ca0de06eb42659f18.json +1 -0
- package/graphify-out/cache/055bfc2a3bfb8747f7ee0b7335704d2dff1c071d25a9bdd4f954e4cc2d630772.json +1 -0
- package/graphify-out/cache/0b2f626892ed04f158e39593dbf5f266c2a5982a21b2dddb144edc79af81e2d1.json +1 -0
- package/graphify-out/cache/0c17fe866170c4ab4023ac0680d1e05c5dc232a17ac0f08dfa1e76c2eaf75c44.json +1 -0
- package/graphify-out/cache/1392dca26291b5396829f1a996aac2c1d34a03d134a5fcf54e4f15824ee74e2b.json +1 -0
- package/graphify-out/cache/18113cd08ebffb11ed91ffab9c6d34795e22bfb5993941db07a52eed6eba45b8.json +1 -0
- package/graphify-out/cache/1a7a71b157cadd117435818e1a6561157c2930c4066d3a207fe04e318f76b296.json +1 -0
- package/graphify-out/cache/2448db4b822a94d6f3512ce8788077f35dfb567aef8628a846fad841b40575e7.json +1 -0
- package/graphify-out/cache/2592868b7b9d2de3f2cb575b7bd68ca2f252d34f71c12f2e8721d789cfbfbf88.json +1 -0
- package/graphify-out/cache/2aaf58292523f67421e6f728fd97740c5bf07dd903cf267cf557a4383759ba5e.json +1 -0
- package/graphify-out/cache/349a418954e66e5ef45370dca740ebff559a72d11f5810f6d40c0af14ef768e0.json +1 -0
- package/graphify-out/cache/361eacb4abb14862b75257bdf673a353826bf5764fb187ccde94ae21454bcf99.json +1 -0
- package/graphify-out/cache/40b4c82a11a2a31b279563c143d91d7894eb3f3d0c386f8323cb8062bcdfadd5.json +1 -0
- package/graphify-out/cache/40db98ff036ad694953cb13628795fabc0c5892ff093dfdcc18a309ac0d10846.json +1 -0
- package/graphify-out/cache/43a590ac22f05be183ea1a4655922185595c969f79dd3df3d44d1c7e49355785.json +1 -0
- package/graphify-out/cache/4993a6e98dcf33bb6fa78341b4eeac4776e2322f10522eecdc5195aa7969f35a.json +1 -0
- package/graphify-out/cache/5095c6e52a24f4ecec9acf63835761ad508df88d56b1799faec47672fbd4e348.json +1 -0
- package/graphify-out/cache/5cba1d38ffea01d8c62e5a0b0d8b164cf9b115ff1b6f1acc606f78877712d5de.json +1 -0
- package/graphify-out/cache/67aadf0b8f90224cb725e903e6fedbf6828f203467a633f98031b0740930cb21.json +1 -0
- package/graphify-out/cache/68dffbffbd811942d85ef2600ca31e423d3c3c343de98cbba4c954c94dd11470.json +1 -0
- package/graphify-out/cache/69c684e506b9ce22e95aff044c1da4b0f88ef72c510da02a739edbe551372a8e.json +1 -0
- package/graphify-out/cache/6e336587fcfe2b298f23326e881f048d37f1bb062d00806c338da58a8fd281ca.json +1 -0
- package/graphify-out/cache/78d88737e6db913f091c4c48e96953df065f6808e2b60dd828fdee64067dac91.json +1 -0
- package/graphify-out/cache/7e5340b989299a0b7217d1fd0d2b919cba65142f3e468b0aca5f4ffd5c0594d8.json +1 -0
- package/graphify-out/cache/813d6bac52066ed8733781c35710ecb7995e6cabbe0d9abb9854e3c67610b974.json +1 -0
- package/graphify-out/cache/8180f34832546e874bc5f1931eee545d97300be49faac5c9b6d515653a763324.json +1 -0
- package/graphify-out/cache/885894ca90af6a3724182762bc4fc7ff7d22727a931d46fe7593d1eea10c0c71.json +1 -0
- package/graphify-out/cache/8a304ae8f6bf02bfa40923cdbea99e4bea943db52c185f22caa43ba7c34f94d3.json +1 -0
- package/graphify-out/cache/903a7dea28112a27dcc1b9ece66514f4d5dd6ca264f5ee70835aca069a8df2ad.json +1 -0
- package/graphify-out/cache/9831a7833c5bfeb9a0611e416f7038bd37884b42a9a720f9b4c0a01f860a4f54.json +1 -0
- package/graphify-out/cache/98dbdcdd1b19bc942850f50b1ebdeb1865c72ba724990217464efd28a3732b32.json +1 -0
- package/graphify-out/cache/a2459f621d588f0166ae6a4204bb6b89f9d669b3ad0c54a88afac6c7abb134b4.json +1 -0
- package/graphify-out/cache/a25d47ecf087fa6888d641f89f08cefd35c68b5823c8c55b3baa0243ab110110.json +1 -0
- package/graphify-out/cache/a3bd22d8493943a3195c3ef1254a7240624a962edf2baa2c30eb0ae60564fbe7.json +1 -0
- package/graphify-out/cache/a4d4fb674183a3b348f542b1b9fb9c0d7b176c43636afb2554af088a9613a1c0.json +1 -0
- package/graphify-out/cache/a87a705106773b14c5a25697d30c743cdab01df551cdd9892d6ec46f98ad1659.json +1 -0
- package/graphify-out/cache/a9416d0397b5fb994b8c3847aea2599a9d33940e6f0652accc5ba1de478349ee.json +1 -0
- package/graphify-out/cache/ab03b9df0e9b8a74db3782c96fee833d800d93838fc0c056306ac2ef9a3e0c09.json +1 -0
- package/graphify-out/cache/ad3a99182567225cc19374c28d33097f146547bd945967c723b66d1065134ce9.json +1 -0
- package/graphify-out/cache/aece91cfc3a5181bbb77a1758921dfb6a323ab04cc402ce42f2832446d04f420.json +1 -0
- package/graphify-out/cache/bd65fd515423e8964058f6aa997c05e3e0fb9e6d39209d4a1d76a079c6af46e8.json +1 -0
- package/graphify-out/cache/c2a85071784f9516ab2dea976eeb3a514a53b15701bbf60b4d8be6cd3385cd6c.json +1 -0
- package/graphify-out/cache/c9a8c9342926031f308af0eb0a8d60cf0b443e84bae839da42998956465e47e6.json +1 -0
- package/graphify-out/cache/d05c0aa647a624e0c696f53c027d066c35d0893695e9a23fd820235ee86b4a70.json +1 -0
- package/graphify-out/cache/d3d9832015ab51f52ae88375cea2cbeabecd4a000578e28e899ce23e74245733.json +1 -0
- package/graphify-out/cache/d449ad503a40840d41cbf24ed57f408bf5fdf891f830990f836cf52da5c605eb.json +1 -0
- package/graphify-out/cache/d92b22194973f3c39ac53d85a29f5d4837d07b0f9f0d375e3ddce8da158777fb.json +1 -0
- package/graphify-out/cache/dda8f89f688d8a4db8b7279031ad26a0d8d4accc0aa049abda5fa19eac4bd5ef.json +1 -0
- package/graphify-out/cache/e1d80dbca10b7e2ba65339eff0649699c6091d30b836a1e9d5d094bb95aacc48.json +1 -0
- package/graphify-out/cache/e207108277cbe1af0501688b0268fea879d0414424386fbaa93a5861f306bdba.json +1 -0
- package/graphify-out/cache/e6032dad287da859a517d6b59105595db90e81833dbd850b37653bbd0f3acef7.json +1 -0
- package/graphify-out/cache/f49d7295a833de68579e0e265832bc78d21e901764e31705423e621a703124dc.json +1 -0
- package/graphify-out/cache/fcf90a1251a332948a773c6aaaad4ce7f6de8d2f2333687cb2fe94e0d860a6c9.json +1 -0
- package/graphify-out/cache/fe06fcb623d36858b89c8741696482530a084f599d48bea88de7943fae0f9bea.json +1 -0
- package/graphify-out/cache/ffa0f819e023809d17aac1af75cf0f6fbf08500615aee27341b658f24357105a.json +1 -0
- package/graphify-out/cost.json +12 -0
- package/graphify-out/graph.html +266 -0
- package/graphify-out/graph.json +634 -0
- package/graphify-out/manifest.json +124 -0
- package/how-to-create-a-plugin.md +573 -0
- package/package.json +22 -18
- package/src/main.js +5 -5
- package/src/plugins/click/_listenDOM.js +3 -3
- package/src/plugins/form/_listenDOM.js +7 -6
- package/src/plugins/hover/_listenDOM.js +2 -2
- package/src/plugins/key/_listenDOM.js +4 -4
- package/src/plugins/scroll/_listenDOM.js +1 -1
- package/test/01-general.test.js +1 -1
- package/test/02-key.test.js +45 -1
- package/test/03-click.test.js +51 -2
- package/test/04-form.test.js +26 -1
- package/test/05-hover.test.js +50 -2
- package/test/06-scroll.test.js +21 -0
- package/How.to.create.plugins.md +0 -929
package/README.md
CHANGED
|
@@ -22,37 +22,167 @@ Currently existing plugins:
|
|
|
22
22
|
|
|
23
23
|
|
|
24
24
|
|
|
25
|
-
##
|
|
26
|
-
|
|
25
|
+
## Table of Contents
|
|
26
|
+
1. [Quick Start](#quick-start)
|
|
27
|
+
2. [Concepts](#concepts)
|
|
28
|
+
3. [Constructor Options](#constructor-options)
|
|
29
|
+
4. [Per-Plugin Options](#per-plugin-options)
|
|
30
|
+
5. [Shortcut Description Rules](#shortcut-description-rules)
|
|
31
|
+
6. [Per-Context Setup vs `enablePlugin` Options](#per-context-setup-vs-enableplugin-options)
|
|
32
|
+
7. [Plugin Reference](#plugin-reference)
|
|
33
|
+
- [Plugin 'key'](#plugin-key-shortcut-descriptions)
|
|
34
|
+
- [Plugin 'click'](#plugin-click-shortcut-descriptions)
|
|
35
|
+
- [Plugin 'hover'](#plugin-hover-shortcut-descriptions)
|
|
36
|
+
- [Plugin 'scroll'](#plugin-scroll-shortcut-descriptions)
|
|
37
|
+
- [Plugin 'form'](#plugin-form-shortcut-descriptions)
|
|
38
|
+
8. [Action Function Signatures](#action-functions)
|
|
39
|
+
9. [Methods](#methods)
|
|
40
|
+
10. [Contexts, Notes, and Dependencies](#contexts-notes-and-dependencies)
|
|
41
|
+
11. [Errors and the `errorEventName` Channel](#errors-and-the-erroreventname-channel)
|
|
42
|
+
12. [Custom Events & Workflows](#custom-events--workflows)
|
|
43
|
+
13. [TypeScript Support](#typescript-support)
|
|
44
|
+
14. [Links](#links)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
## Quick Start
|
|
27
49
|
|
|
28
|
-
|
|
29
|
-
|
|
50
|
+
```js
|
|
51
|
+
// for es6 module projects:
|
|
52
|
+
import { shortcuts, pluginKey, pluginClick, pluginForm, pluginHover, pluginScroll } from '@peter.naydenov/shortcuts'
|
|
53
|
+
// for commonjs projects:
|
|
54
|
+
const { shortcuts, pluginKey, pluginClick, pluginForm, pluginHover, pluginScroll } = require('@peter.naydenov/shortcuts')
|
|
30
55
|
|
|
31
|
-
- **Context-specific configuration** - Different settings for different contexts
|
|
32
|
-
- **Cleaner code** - No global plugin options needed
|
|
33
|
-
- **Better maintainability** - Settings are defined alongside the shortcuts they affect
|
|
34
56
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
57
|
+
const short = shortcuts ();
|
|
58
|
+
// Load needed plugins. Second argument is per-plugin options.
|
|
59
|
+
short.enablePlugin ( pluginKey )
|
|
60
|
+
short.enablePlugin ( pluginClick )
|
|
61
|
+
// Load a shortcut definition
|
|
62
|
+
short.load ( shortcutDefinition )
|
|
63
|
+
// Activate a context to start listening.
|
|
64
|
+
short.changeContext ( 'editor' )
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
To stop all shortcuts without activating another context:
|
|
38
68
|
|
|
39
|
-
Example pattern:
|
|
40
69
|
```js
|
|
41
|
-
|
|
42
|
-
context1: {
|
|
43
|
-
'plugin:setup': ({ dependencies, defaults }) => {
|
|
44
|
-
return {
|
|
45
|
-
// Override specific options for this context
|
|
46
|
-
option1: 'customValue1',
|
|
47
|
-
option2: 123
|
|
48
|
-
};
|
|
49
|
-
},
|
|
50
|
-
'plugin:event': () => { /* your action */ }
|
|
51
|
-
}
|
|
52
|
-
};
|
|
70
|
+
short.changeContext () // deactivates the current context
|
|
53
71
|
```
|
|
54
72
|
|
|
55
|
-
See
|
|
73
|
+
See [Shortcut Description Rules](#shortcut-description-rules) for the shape of `shortcutDefinition`, and [Methods](#methods) for the full API.
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
## Concepts
|
|
78
|
+
|
|
79
|
+
- **Shortcut** — a single rule like `'key: ctrl+s'` or `'click: left-1'` that is triggered by a physical event.
|
|
80
|
+
- **Action function** — the function (or array of functions) executed when a shortcut fires. Each plugin passes a different `data` object to it (see [Action Functions](#action-functions)).
|
|
81
|
+
- **Context** — a named bucket of shortcuts. Only one context is active at a time; `changeContext(name)` switches between them.
|
|
82
|
+
- **Note** — a sub-context tag that lives inside the current context. Lets a single context react differently to the same shortcut under different notes. Set with `setNote('foo')`, read inside the action as `data.note`.
|
|
83
|
+
- **Plugin** — the layer that converts physical input into shortcut events (`key`, `click`, `hover`, `scroll`, `form`).
|
|
84
|
+
- **Custom event** — any string (typically namespaced with `@` or `app:`) that you can `emit` and `listen` to. See [Custom Events & Workflows](#custom-events--workflows).
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
## Constructor Options
|
|
89
|
+
|
|
90
|
+
`shortcuts(options)` accepts:
|
|
91
|
+
|
|
92
|
+
| Option | Type | Default | Description |
|
|
93
|
+
|---|---|---|---|
|
|
94
|
+
| `onShortcut` | `function` | `false` | Called for every triggered shortcut in the current context (including programmatically emitted events). |
|
|
95
|
+
| `errorEventName` | `string` | `'@shortcuts-error'` | Name of the event on which the library publishes error messages. See [Errors and the `errorEventName` Channel](#errors-and-the-erroreventname-channel). |
|
|
96
|
+
| `streamKeys` | `function` | `false` | Called on every key press while the `key` plugin is active. Equivalent to passing `streamKeys` to `enablePlugin(pluginKey, …)`. |
|
|
97
|
+
|
|
98
|
+
```js
|
|
99
|
+
const short = shortcuts ({
|
|
100
|
+
onShortcut : ({ shortcut, context }) => console.log ( shortcut, 'in', context )
|
|
101
|
+
, errorEventName : '@my-app-shortcut-errors'
|
|
102
|
+
});
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### `onShortcut({ shortcut, context, note, dependencies })`
|
|
106
|
+
```js
|
|
107
|
+
function onShortcut ({ shortcut, context, note, dependencies }) {
|
|
108
|
+
// shortcut - (string) Triggered shortcut name (e.g. 'KEY:CTRL+S')
|
|
109
|
+
// context - (string) Name of the current context
|
|
110
|
+
// note - (string) Name of the note or null if note isn't set
|
|
111
|
+
// dependencies - (object) Object with dependencies that you have set by calling `setDependencies` method
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### `streamKeys({ key, context, note, dependencies })`
|
|
116
|
+
```js
|
|
117
|
+
function streamKeys ({ key, context, note, dependencies }) {
|
|
118
|
+
// key - (string) Pressed key name
|
|
119
|
+
// context - (string) Name of the current context
|
|
120
|
+
// note - (string) Name of the note or null if note isn't set
|
|
121
|
+
// dependencies - (object) Object with dependencies that you have set by calling `setDependencies` method
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
## Per-Plugin Options
|
|
128
|
+
|
|
129
|
+
These are passed as the second argument of `enablePlugin(plugin, options)`. To override per-context, use the `plugin:setup` event — see [Per-Context Setup vs `enablePlugin` Options](#per-context-setup-vs-enableplugin-options).
|
|
130
|
+
|
|
131
|
+
### Plugin 'key' options
|
|
132
|
+
```js
|
|
133
|
+
keyWait : 'Timeout for entering shortcut sequence in ms. Default value - 480'
|
|
134
|
+
, streamKeys : 'False or a callback function that is called when a key is pressed. Default value - false'
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Plugin 'click' options
|
|
138
|
+
```js
|
|
139
|
+
mouseWait : 'Timeout for entering multiple mouse events. Default value - 320.'
|
|
140
|
+
, clickTarget : 'Array of attribute names to recognize click items in HTML. Default value - ["data-click", "href"]' // checks for data-click='someName' or href attributes
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Plugin 'hover' options
|
|
144
|
+
```js
|
|
145
|
+
wait : 'Time to wait for hover sequence in ms. Default value - 320.'
|
|
146
|
+
, hoverTarget : 'Array of attribute names to recognize hover items in HTML. Default value - ["data-hover"]' // checks for data-hover='someName' attribute
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Plugin 'scroll' options
|
|
150
|
+
```js
|
|
151
|
+
scrollWait : 'Delay between scroll events in ms. Default value - 50.'
|
|
152
|
+
, endScrollWait : 'Delay when scroll was stopped in ms. Default value - 400.'
|
|
153
|
+
, minSpace : 'Minimum distance between scroll events in px. Default value - 40.'
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Plugin options are provided as a second argument during the plugin enabling:
|
|
157
|
+
|
|
158
|
+
```js
|
|
159
|
+
short.enablePlugin ( pluginKey, {
|
|
160
|
+
keyWait: 500 // set the interval to 500ms
|
|
161
|
+
, streamKeys: (key) => console.log(key) // Log in console each pressed key
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
short.enablePlugin ( pluginClick, {
|
|
165
|
+
mouseWait: 200 // set the interval between multiple clicks to 200ms
|
|
166
|
+
, clickTarget: ['data-puk', 'data-button'] // array of attribute names to check
|
|
167
|
+
})
|
|
168
|
+
|
|
169
|
+
short.enablePlugin ( pluginHover, {
|
|
170
|
+
wait: 500 // set the hover delay to 500ms
|
|
171
|
+
, hoverTarget: ['data-hover-me', 'data-interactive'] // array of attribute names to check
|
|
172
|
+
})
|
|
173
|
+
|
|
174
|
+
short.enablePlugin ( pluginScroll, {
|
|
175
|
+
scrollWait: 100 // set the delay between scroll events to 100ms
|
|
176
|
+
, endScrollWait: 600 // set the end scroll delay to 600ms
|
|
177
|
+
, minSpace: 60 // set minimum distance to 60px
|
|
178
|
+
})
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
## Shortcut Description Rules
|
|
184
|
+
|
|
185
|
+
The shortcuts definition includes a context name and a set of rules (object). The rules are a set of key-value pairs. The key contains a plugin name and a shortcut name and the value is a function or array of functions, to be executed when the shortcut is triggered (action function).
|
|
56
186
|
|
|
57
187
|
```js
|
|
58
188
|
// { context: { shortcutName: actionFunction } }
|
|
@@ -65,7 +195,7 @@ See individual plugin sections for specific setup examples.
|
|
|
65
195
|
shortcutName : function () {
|
|
66
196
|
// do something
|
|
67
197
|
}
|
|
68
|
-
, shortcutName : [
|
|
198
|
+
, shortcutName : [
|
|
69
199
|
function action1() {
|
|
70
200
|
// do something
|
|
71
201
|
}
|
|
@@ -75,302 +205,169 @@ See individual plugin sections for specific setup examples.
|
|
|
75
205
|
]
|
|
76
206
|
}
|
|
77
207
|
}
|
|
78
|
-
// shortcutName after v.3.0.0 have a plugin prefix. - 'pluginPrefix:shortcutName'.
|
|
208
|
+
// shortcutName after v.3.0.0 have a plugin prefix. - 'pluginPrefix:shortcutName'.
|
|
79
209
|
// For example: 'key:s+alt' - for 's+alt' shortcut that is handled by 'key' plugin.
|
|
80
210
|
```
|
|
81
211
|
|
|
82
212
|
Load a shortcut definition by calling `load` method.
|
|
83
213
|
|
|
84
214
|
```js
|
|
85
|
-
// for es6 module projects:
|
|
86
|
-
import { shortcuts, pluginKey, pluginClick, pluginForm, pluginHover, pluginScroll } from '@peter.naydenov/shortcuts'
|
|
87
|
-
// for commonjs projects:
|
|
88
|
-
const { shortcuts, pluginKey, pluginClick, pluginForm, pluginHover, pluginScroll } = require('@peter.naydenov/shortcuts')
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
215
|
const short = shortcuts ();
|
|
93
|
-
|
|
94
|
-
// short.enablePlugin ( pluginCode, ?pluginOptions )
|
|
95
|
-
short.enablePlugin ( pluginKey )
|
|
216
|
+
short.enablePlugin ( pluginKey )
|
|
96
217
|
short.enablePlugin ( pluginClick )
|
|
97
|
-
// Load a shortcut definition
|
|
98
218
|
short.load ( shortcutDefinition )
|
|
99
|
-
|
|
219
|
+
short.changeContext ( contextName ) // activate a context
|
|
100
220
|
```
|
|
101
221
|
|
|
102
|
-
Shortcuts
|
|
222
|
+
Shortcuts only fire while a context is active. To deactivate a context without starting another, call `changeContext` with no argument.
|
|
103
223
|
|
|
104
224
|
```js
|
|
105
|
-
short.changeContext (
|
|
225
|
+
short.changeContext () // deactivates the current context
|
|
106
226
|
```
|
|
107
227
|
|
|
108
|
-
To deactivate a context without starting other context, call `changeContext` method without arguments.
|
|
109
228
|
|
|
110
|
-
```js
|
|
111
|
-
short.changeContext ()
|
|
112
|
-
```
|
|
113
229
|
|
|
230
|
+
## Per-Context Setup vs `enablePlugin` Options
|
|
114
231
|
|
|
115
|
-
|
|
116
|
-
`Hover` plugin is used to detect when mouse enters or leaves specific HTML elements. The plugin supports two main events: hover on and hover off.
|
|
232
|
+
There are two ways to configure a plugin:
|
|
117
233
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
hover:off // Triggered when mouse leaves a target element
|
|
121
|
-
```
|
|
234
|
+
1. **Globally** — pass options to `enablePlugin(plugin, options)`. They apply to every context that uses that plugin.
|
|
235
|
+
2. **Per-context** — define a `plugin:setup` event inside the context object. The function receives `{ dependencies, defaults }` and returns an options object that overrides the defaults **for that context only**. The supported events are `key:setup`, `click:setup`, `hover:setup`, and `scroll:setup`.
|
|
122
236
|
|
|
123
|
-
|
|
124
|
-
|
|
237
|
+
**Per-context setup is the preferred method** because:
|
|
238
|
+
- Different contexts can use different settings (e.g. fast clicks in a game context, deliberate clicks in a form context).
|
|
239
|
+
- The configuration lives next to the shortcuts that depend on it.
|
|
240
|
+
- You don't have to re-enable the plugin when switching contexts.
|
|
125
241
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
Attribute is customizable by setting `hoverTarget` hover plugin option. By default, it checks for `['data-hover']`. You can provide an array of attribute names. Read more in section `Options`.
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
### Hover Action Functions
|
|
136
|
-
Hover plugin action functions receive the following arguments:
|
|
137
|
-
|
|
138
|
-
```js
|
|
139
|
-
function myHoverHandler ({
|
|
140
|
-
context // (string) Name of the current context;
|
|
141
|
-
, note // (string) Name of the note or null if note isn't set;
|
|
142
|
-
, dependencies // (object) Object with dependencies that you have set by calling `setDependencies` method;
|
|
143
|
-
, target // (DOM element). Target element of the hover event;
|
|
144
|
-
, targetProps // (object). Coordinates of the target element (top, left, right, bottom, width, height) or null if target element is not available;
|
|
145
|
-
, x // (number). X coordinate of the target element;
|
|
146
|
-
, y // (number). Y coordinate of the target element;
|
|
147
|
-
, event // (object). Original hover event object;
|
|
148
|
-
}) {
|
|
149
|
-
// Body of the handler. Do something...
|
|
150
|
-
}
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
### Hover Detection Timing
|
|
154
|
-
Hover events are detected with a delay to avoid triggering when mouse quickly moves over elements. The default delay is 320ms but you can change it by setting `wait` hover plugin option.
|
|
155
|
-
|
|
156
|
-
```js
|
|
157
|
-
short.enablePlugin ( pluginHover, { wait: 500 }) // set the delay to 500ms
|
|
158
|
-
```
|
|
242
|
+
The setup function receives:
|
|
243
|
+
- `dependencies` - External dependencies set via `setDependencies()`
|
|
244
|
+
- `defaults` - Default plugin options as a starting point or just for reference. Use them to read or partially override.
|
|
159
245
|
|
|
160
|
-
|
|
161
|
-
Instead of global plugin options, you can use `hover:setup` event to configure plugin settings per context. This is the preferred method for customization.
|
|
246
|
+
Example pattern (applies to every plugin that supports `setup`):
|
|
162
247
|
|
|
163
248
|
```js
|
|
164
249
|
const shortcutDefinition = {
|
|
165
|
-
|
|
166
|
-
'
|
|
167
|
-
// Customize hover settings for this context only
|
|
168
|
-
return {
|
|
169
|
-
wait: 200, // Faster hover detection for navigation
|
|
170
|
-
hoverTarget: ['data-nav-item', 'data-menu'] // Array of attribute names
|
|
171
|
-
};
|
|
172
|
-
},
|
|
173
|
-
'hover:on': ({ target }) => {
|
|
174
|
-
target.classList.add('active');
|
|
175
|
-
},
|
|
176
|
-
'hover:off': ({ target }) => {
|
|
177
|
-
target.classList.remove('active');
|
|
178
|
-
}
|
|
179
|
-
},
|
|
180
|
-
slowTooltips: {
|
|
181
|
-
'hover:setup': ({ dependencies, defaults }) => {
|
|
182
|
-
// Slower hover detection for tooltips
|
|
250
|
+
context1: {
|
|
251
|
+
'plugin:setup': ({ dependencies, defaults }) => {
|
|
183
252
|
return {
|
|
184
|
-
|
|
185
|
-
|
|
253
|
+
// Override specific options for this context
|
|
254
|
+
option1: 'customValue1',
|
|
255
|
+
option2: 123
|
|
186
256
|
};
|
|
187
257
|
},
|
|
188
|
-
'
|
|
189
|
-
// Show tooltip with delay
|
|
190
|
-
setTimeout(() => target.classList.add('visible'), 100);
|
|
191
|
-
}
|
|
258
|
+
'plugin:event': () => { /* your action */ }
|
|
192
259
|
}
|
|
193
260
|
};
|
|
194
|
-
|
|
195
|
-
short.enablePlugin(pluginHover);
|
|
196
|
-
short.load(shortcutDefinition);
|
|
197
|
-
short.changeContext('navigation'); // Uses navigation settings
|
|
198
|
-
// short.changeContext('slowTooltips'); // Uses tooltip settings
|
|
199
261
|
```
|
|
200
262
|
|
|
201
|
-
|
|
202
|
-
- `dependencies` - External dependencies set via `setDependencies()`
|
|
203
|
-
- `defaults` - Default plugin options as a starting point or just for reference
|
|
263
|
+
See individual plugin sections for specific setup examples (`key:setup`, `click:setup`, `hover:setup`, `scroll:setup`).
|
|
204
264
|
|
|
205
|
-
|
|
265
|
+
**Rule of thumb:** use `enablePlugin(plugin, options)` only for values you want to be global to the app. Use `plugin:setup` for anything that varies by context.
|
|
206
266
|
|
|
207
|
-
```js
|
|
208
|
-
const shortcutDefinition = {
|
|
209
|
-
navigation: {
|
|
210
|
-
'hover:on': ({ target }) => {
|
|
211
|
-
// Mouse entered the target
|
|
212
|
-
target.classList.add('active');
|
|
213
|
-
},
|
|
214
|
-
'hover:off': ({ target }) => {
|
|
215
|
-
// Mouse left the target
|
|
216
|
-
target.classList.remove('active');
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
};
|
|
220
267
|
|
|
221
|
-
short.enablePlugin(pluginHover);
|
|
222
|
-
short.load(shortcutDefinition);
|
|
223
|
-
short.changeContext('navigation');
|
|
224
|
-
```
|
|
225
268
|
|
|
226
|
-
## Plugin
|
|
227
|
-
`Scroll` plugin is used to detect scroll events on the page. The plugin supports four main scroll directions:
|
|
269
|
+
## Plugin Reference
|
|
228
270
|
|
|
229
|
-
```js
|
|
230
|
-
scroll:up // Triggered when scrolling up
|
|
231
|
-
scroll:down // Triggered when scrolling down
|
|
232
|
-
scroll:left // Triggered when scrolling left
|
|
233
|
-
scroll:right // Triggered when scrolling right
|
|
234
|
-
scroll:end // Triggered when scrolling stops (after endScrollWait timeout)
|
|
235
|
-
```
|
|
236
271
|
|
|
237
|
-
### Scroll Detection Settings
|
|
238
|
-
Scroll events are detected with specific timing and distance thresholds to avoid excessive triggering. The default settings are:
|
|
239
272
|
|
|
240
|
-
|
|
241
|
-
- `endScrollWait`: 400ms - Delay when scroll was stopped
|
|
242
|
-
- `minSpace`: 40px - Minimum distance between scroll events
|
|
273
|
+
### Plugin 'key' Shortcut Descriptions
|
|
243
274
|
|
|
244
|
-
|
|
275
|
+
Keyboard event description contains a key name and a modifier keys if they are used. The modifier keys `ctrl`, `alt`, and `shift` are supported. They are added to the keyboard event by sign `+`:
|
|
245
276
|
|
|
246
277
|
```js
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
endScrollWait: 600, // set end scroll delay to 600ms
|
|
250
|
-
minSpace: 60 // set minimum distance to 60px
|
|
251
|
-
})
|
|
278
|
+
// example:
|
|
279
|
+
// key: ctrl+alt+shift+a -> for key 'a' with ctrl, alt and shift keys pressed
|
|
252
280
|
```
|
|
253
281
|
|
|
254
|
-
|
|
255
|
-
Instead of global plugin options, you can use `scroll:setup` event to configure plugin settings per context. This is preferred method for customization.
|
|
282
|
+
Keyboard event description support a shortcut sequenses. These means that you can press a sequence of keys to trigger a shortcut. The sequence elements are separated by sign "," ( coma ):
|
|
256
283
|
|
|
257
284
|
```js
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
'scroll:setup': ({ dependencies, defaults }) => {
|
|
261
|
-
// High sensitivity for gaming or precise interactions
|
|
262
|
-
return {
|
|
263
|
-
scrollWait: 20, // Very responsive
|
|
264
|
-
endScrollWait: 200, // Quick end detection
|
|
265
|
-
minSpace: 20 // Small movements trigger
|
|
266
|
-
};
|
|
267
|
-
},
|
|
268
|
-
'scroll:up': () => console.log('Sensitive scroll up'),
|
|
269
|
-
'scroll:down': () => console.log('Sensitive scroll down'),
|
|
270
|
-
'scroll:end': () => console.log('Sensitive scroll ended')
|
|
271
|
-
},
|
|
272
|
-
lazyScrolling: {
|
|
273
|
-
'scroll:setup': ({ dependencies, defaults }) => {
|
|
274
|
-
// Low sensitivity for reading or casual browsing
|
|
275
|
-
return {
|
|
276
|
-
scrollWait: 150, // Less responsive
|
|
277
|
-
endScrollWait: 800, // Slow end detection
|
|
278
|
-
minSpace: 80 // Larger movements needed
|
|
279
|
-
};
|
|
280
|
-
},
|
|
281
|
-
'scroll:up': () => console.log('Lazy scroll up'),
|
|
282
|
-
'scroll:down': () => console.log('Lazy scroll down'),
|
|
283
|
-
'scroll:end': () => console.log('Lazy scroll ended')
|
|
284
|
-
}
|
|
285
|
-
};
|
|
286
|
-
|
|
287
|
-
short.enablePlugin(pluginScroll);
|
|
288
|
-
short.load(shortcutDefinition);
|
|
289
|
-
short.changeContext('sensitiveScrolling'); // Uses sensitive settings
|
|
290
|
-
// short.changeContext('lazyScrolling'); // Uses lazy settings
|
|
291
|
-
```
|
|
292
|
-
|
|
293
|
-
The `scroll:setup` function receives:
|
|
294
|
-
- `dependencies` - External dependencies set via `setDependencies()`
|
|
295
|
-
- `defaults` - Default plugin options as a starting point
|
|
296
|
-
|
|
297
|
-
### Scroll Action Functions
|
|
298
|
-
Scroll plugin action functions receive the following arguments:
|
|
285
|
+
// example:
|
|
286
|
+
// key: a,b,c -> for key 'a' then key 'b' then key 'c'
|
|
299
287
|
|
|
300
|
-
|
|
301
|
-
function myScrollHandler ({
|
|
302
|
-
context // (string) Name of the current context;
|
|
303
|
-
, note // (string) Name of the note or null if note isn't set;
|
|
304
|
-
, dependencies // (object) Object with dependencies that you have set by calling `setDependencies` method;
|
|
305
|
-
, event // (object). Original scroll event object;
|
|
306
|
-
}) {
|
|
307
|
-
// Body of the handler. Do something...
|
|
308
|
-
}
|
|
288
|
+
// key: g+shift,o,t,o -> for key 'g' with shift, then key 'o', then key 't' then key 'o'
|
|
309
289
|
```
|
|
310
290
|
|
|
311
|
-
|
|
291
|
+
Order of describing keyboard event and modifier keys is not important, but sequence elements are:
|
|
312
292
|
|
|
313
293
|
```js
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
console.log('User scrolled down');
|
|
321
|
-
},
|
|
322
|
-
'scroll:end': () => {
|
|
323
|
-
console.log('User stopped scrolling');
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
};
|
|
327
|
-
|
|
328
|
-
short.enablePlugin(pluginScroll);
|
|
329
|
-
short.load(shortcutDefinition);
|
|
330
|
-
short.changeContext('scrollView');
|
|
294
|
+
// example:
|
|
295
|
+
// key: a+ctrl,l,o,t -> a with ctrl, then l, then o, then t
|
|
296
|
+
// this is equal to:
|
|
297
|
+
// key: ctrl+a,l,o,t
|
|
298
|
+
// but not equal to:
|
|
299
|
+
// key: ctrl+a,o,t,l
|
|
331
300
|
```
|
|
332
301
|
|
|
333
|
-
|
|
302
|
+
Keyboard sequence is detected automatically by time interval between key presses. The default interval is 480ms but you can change it by setting `keyWait` key plugin option. Read more in section `Per-Plugin Options`.
|
|
334
303
|
|
|
335
|
-
|
|
304
|
+
#### Per-Context Setup (Preferred Method)
|
|
305
|
+
Instead of global plugin options, you can use `key:setup` event to configure plugin settings per context. This is preferred method for customization.
|
|
336
306
|
|
|
337
307
|
```js
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
308
|
+
const shortcutDefinition = {
|
|
309
|
+
fastTyping: {
|
|
310
|
+
'key:setup': ({ dependencies, defaults }) => {
|
|
311
|
+
// Fast key detection for gaming or rapid input
|
|
312
|
+
return {
|
|
313
|
+
keyWait: 200, // Very fast sequence detection
|
|
314
|
+
streamKeys: (key) => console.log('Key pressed:', key) // Enable key streaming
|
|
315
|
+
};
|
|
316
|
+
},
|
|
317
|
+
'key:a,b,c': () => console.log('Fast sequence triggered'),
|
|
318
|
+
'key:ctrl+s': () => console.log('Fast save')
|
|
319
|
+
},
|
|
320
|
+
slowTyping: {
|
|
321
|
+
'key:setup': ({ dependencies, defaults }) => {
|
|
322
|
+
// Slower key detection for accessibility or careful input
|
|
323
|
+
return {
|
|
324
|
+
keyWait: 800, // Slower sequence detection
|
|
325
|
+
streamKeys: false // Disable key streaming
|
|
326
|
+
};
|
|
327
|
+
},
|
|
328
|
+
'key:a,b,c': () => console.log('Slow sequence triggered'),
|
|
329
|
+
'key:ctrl+s': () => console.log('Careful save')
|
|
330
|
+
}
|
|
331
|
+
};
|
|
343
332
|
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
if ( note === 'special' ) {
|
|
349
|
-
// do something
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
}
|
|
333
|
+
short.enablePlugin(pluginKey);
|
|
334
|
+
short.load(shortcutDefinition);
|
|
335
|
+
short.changeContext('fastTyping'); // Uses fast settings
|
|
336
|
+
// short.changeContext('slowTyping'); // Uses slow settings
|
|
354
337
|
```
|
|
355
338
|
|
|
356
|
-
|
|
357
|
-
|
|
339
|
+
The `key:setup` function receives:
|
|
340
|
+
- `dependencies` - External dependencies set via `setDependencies()`
|
|
341
|
+
- `defaults` - Default plugin options as a starting point
|
|
358
342
|
|
|
359
|
-
|
|
360
|
-
short.getContext ()
|
|
361
|
-
```
|
|
343
|
+
There is a way to disable automatic sequence detection and mark the begining and the end of the sequense by using a keyboard action functions. Read more in section [Action Functions → Keyboard Action Functions](#keyboard-action-functions).
|
|
362
344
|
|
|
363
|
-
|
|
345
|
+
Special characters that are available for your shortcut descriptions:
|
|
346
|
+
- 'left' - left arrow key
|
|
347
|
+
- 'right' - right arrow key
|
|
348
|
+
- 'up' - up arrow key
|
|
349
|
+
- 'down' - down arrow key
|
|
350
|
+
- 'enter' - enter key
|
|
351
|
+
- 'space' - space key
|
|
352
|
+
- 'esc' - escape key
|
|
353
|
+
- 'tab' - tab key
|
|
354
|
+
- 'backspace' - backspace key
|
|
355
|
+
- '=' - equal key
|
|
356
|
+
- F1 - F12 - function keys
|
|
357
|
+
- '/' - slash key
|
|
358
|
+
- '\\' - backslash key
|
|
359
|
+
- '[' - open square bracket key
|
|
360
|
+
- ']' - close square bracket key
|
|
361
|
+
- '`' - backtick key
|
|
364
362
|
|
|
365
|
-
|
|
366
|
-
short.getNote ()
|
|
367
|
-
```
|
|
363
|
+
**Warning**: For keys with two symbols(look at the keyboard), in shortcut description use the lower one. Examples: Use '=' instead of '+', use '/' instead of '?', etc. Modifier keys are available for special characters too.
|
|
368
364
|
|
|
365
|
+
**Warining**: Some of the shortcuts are used by OS and the browswer, so they are not available.
|
|
369
366
|
|
|
370
367
|
|
|
371
368
|
|
|
369
|
+
### Plugin 'click' Shortcut Descriptions
|
|
372
370
|
|
|
373
|
-
## Plugin 'click' Shortcut Descriptions
|
|
374
371
|
Mouse event name is build from the following parts:
|
|
375
372
|
```js
|
|
376
373
|
// click:<mouse button>-<number of clicks>-<modifier key>-<modifier key>-<modifier key>
|
|
@@ -405,7 +402,7 @@ Multiple clicks are detected automatically by time interval between clicks. The
|
|
|
405
402
|
short.enablePlugin ( pluginClick, { mouseWait: 500 }) // set the interval to 500ms
|
|
406
403
|
```
|
|
407
404
|
|
|
408
|
-
|
|
405
|
+
#### Per-Context Setup (Preferred Method)
|
|
409
406
|
Instead of global plugin options, you can use `click:setup` event to configure plugin settings per context. This is preferred method for customization.
|
|
410
407
|
|
|
411
408
|
```js
|
|
@@ -430,7 +427,7 @@ const shortcutDefinition = {
|
|
|
430
427
|
// Slower clicking for form submissions or important actions
|
|
431
428
|
return {
|
|
432
429
|
mouseWait: 600, // Slower click detection
|
|
433
|
-
clickTarget: ['data-form-action', 'data-submit'] // Array of attributes for form
|
|
430
|
+
clickTarget: ['data-form-action', 'data-submit'] // Array of attributes for form submissions
|
|
434
431
|
};
|
|
435
432
|
},
|
|
436
433
|
'click:left-1': ({ target }) => {
|
|
@@ -449,10 +446,12 @@ The `click:setup` function receives:
|
|
|
449
446
|
- `dependencies` - External dependencies set via `setDependencies()`
|
|
450
447
|
- `defaults` - Default plugin options as a starting point
|
|
451
448
|
|
|
452
|
-
Read more in section `Options`.
|
|
449
|
+
Read more in section `Per-Plugin Options`.
|
|
450
|
+
|
|
453
451
|
|
|
454
452
|
|
|
455
|
-
|
|
453
|
+
### Define a Click Targets
|
|
454
|
+
|
|
456
455
|
Target HTML elements for `shortcuts` are defined by `data-click` attribute. The value of the attribute is the name of the target. Example:
|
|
457
456
|
|
|
458
457
|
```html
|
|
@@ -460,7 +459,7 @@ Target HTML elements for `shortcuts` are defined by `data-click` attribute. The
|
|
|
460
459
|
<!-- target name is 'id' -->
|
|
461
460
|
```
|
|
462
461
|
|
|
463
|
-
Attribute is customizable by setting `clickTarget` click plugin option. By default, it checks for `['data-click', 'href']`. You can provide an array of attribute names. Read more in section `Options`.
|
|
462
|
+
Attribute is customizable by setting `clickTarget` click plugin option. By default, it checks for `['data-click', 'href']`. You can provide an array of attribute names. Read more in section `Per-Plugin Options`.
|
|
464
463
|
|
|
465
464
|
If current shortcuts context contain definition for 2 or more clicks, this may slow down the execution of single shortcuts because `shortcuts` will wait for the time interval to detect multiple clicks. To avoid this for specific targets, you can set `data-quick-click` attribute to the target element. Example:
|
|
466
465
|
|
|
@@ -493,121 +492,229 @@ Clicking on <a> tag will execute default browser behaviour. In your `click:left-
|
|
|
493
492
|
|
|
494
493
|
|
|
495
494
|
|
|
496
|
-
|
|
497
|
-
|
|
495
|
+
### Plugin 'hover' Shortcut Descriptions
|
|
496
|
+
|
|
497
|
+
`Hover` plugin is used to detect when mouse enters or leaves specific HTML elements. The plugin supports two main events: hover on and hover off.
|
|
498
498
|
|
|
499
499
|
```js
|
|
500
|
-
|
|
501
|
-
|
|
500
|
+
hover:on // Triggered when mouse enters a target element
|
|
501
|
+
hover:off // Triggered when mouse leaves a target element
|
|
502
502
|
```
|
|
503
503
|
|
|
504
|
-
|
|
504
|
+
#### Define Hover Targets
|
|
505
|
+
Target HTML elements for `hover` plugin are defined by `data-hover` attribute. The value of the attribute is the name of the target. Example:
|
|
506
|
+
|
|
507
|
+
```html
|
|
508
|
+
<div data-hover="menu">Menu content</div>
|
|
509
|
+
<!-- target name is 'menu' -->
|
|
510
|
+
```
|
|
511
|
+
|
|
512
|
+
Attribute is customizable by setting `hoverTarget` hover plugin option. By default, it checks for `['data-hover']`. You can provide an array of attribute names. Read more in section `Per-Plugin Options`.
|
|
513
|
+
|
|
514
|
+
|
|
515
|
+
|
|
516
|
+
### Hover Detection Timing
|
|
517
|
+
Hover events are detected with a delay to avoid triggering when mouse quickly moves over elements. The default delay is 320ms but you can change it by setting `wait` hover plugin option.
|
|
505
518
|
|
|
506
519
|
```js
|
|
507
|
-
//
|
|
508
|
-
|
|
520
|
+
short.enablePlugin ( pluginHover, { wait: 500 }) // set the delay to 500ms
|
|
521
|
+
```
|
|
509
522
|
|
|
510
|
-
|
|
523
|
+
#### Per-Context Setup (Preferred Method)
|
|
524
|
+
Instead of global plugin options, you can use `hover:setup` event to configure plugin settings per context. This is the preferred method for customization.
|
|
525
|
+
|
|
526
|
+
```js
|
|
527
|
+
const shortcutDefinition = {
|
|
528
|
+
navigation: {
|
|
529
|
+
'hover:setup': ({ dependencies, defaults }) => {
|
|
530
|
+
// Customize hover settings for this context only
|
|
531
|
+
return {
|
|
532
|
+
wait: 200, // Faster hover detection for navigation
|
|
533
|
+
hoverTarget: ['data-nav-item', 'data-menu'] // Array of attribute names
|
|
534
|
+
};
|
|
535
|
+
},
|
|
536
|
+
'hover:on': ({ target }) => {
|
|
537
|
+
target.classList.add('active');
|
|
538
|
+
},
|
|
539
|
+
'hover:off': ({ target }) => {
|
|
540
|
+
target.classList.remove('active');
|
|
541
|
+
}
|
|
542
|
+
},
|
|
543
|
+
slowTooltips: {
|
|
544
|
+
'hover:setup': ({ dependencies, defaults }) => {
|
|
545
|
+
// Slower hover detection for tooltips
|
|
546
|
+
return {
|
|
547
|
+
wait: 800, // Slower hover detection
|
|
548
|
+
hoverTarget: ['data-tooltip', 'data-help'] // Different attributes for tooltips
|
|
549
|
+
};
|
|
550
|
+
},
|
|
551
|
+
'hover:on': ({ target }) => {
|
|
552
|
+
// Show tooltip with delay
|
|
553
|
+
setTimeout(() => target.classList.add('visible'), 100);
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
};
|
|
557
|
+
|
|
558
|
+
short.enablePlugin(pluginHover);
|
|
559
|
+
short.load(shortcutDefinition);
|
|
560
|
+
short.changeContext('navigation'); // Uses navigation settings
|
|
561
|
+
// short.changeContext('slowTooltips'); // Uses tooltip settings
|
|
511
562
|
```
|
|
512
563
|
|
|
513
|
-
|
|
564
|
+
The `hover:setup` function receives:
|
|
565
|
+
- `dependencies` - External dependencies set via `setDependencies()`
|
|
566
|
+
- `defaults` - Default plugin options as a starting point or just for reference
|
|
567
|
+
|
|
568
|
+
Example usage:
|
|
514
569
|
|
|
515
570
|
```js
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
571
|
+
const shortcutDefinition = {
|
|
572
|
+
navigation: {
|
|
573
|
+
'hover:on': ({ target }) => {
|
|
574
|
+
// Mouse entered the target
|
|
575
|
+
target.classList.add('active');
|
|
576
|
+
},
|
|
577
|
+
'hover:off': ({ target }) => {
|
|
578
|
+
// Mouse left the target
|
|
579
|
+
target.classList.remove('active');
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
};
|
|
583
|
+
|
|
584
|
+
short.enablePlugin(pluginHover);
|
|
585
|
+
short.load(shortcutDefinition);
|
|
586
|
+
short.changeContext('navigation');
|
|
522
587
|
```
|
|
523
588
|
|
|
524
|
-
Keyboard sequence is detected automatically by time interval between key presses. The default interval is 480ms but you can change it by setting `keyWait` key plugin option. Read more in section `Options`.
|
|
525
589
|
|
|
526
|
-
|
|
527
|
-
|
|
590
|
+
|
|
591
|
+
### Plugin 'scroll' Shortcut Descriptions
|
|
592
|
+
|
|
593
|
+
`Scroll` plugin is used to detect scroll events on the page. The plugin supports four main scroll directions:
|
|
594
|
+
|
|
595
|
+
```js
|
|
596
|
+
scroll:up // Triggered when scrolling up
|
|
597
|
+
scroll:down // Triggered when scrolling down
|
|
598
|
+
scroll:left // Triggered when scrolling left
|
|
599
|
+
scroll:right // Triggered when scrolling right
|
|
600
|
+
scroll:end // Triggered when scrolling stops (after endScrollWait timeout)
|
|
601
|
+
```
|
|
602
|
+
|
|
603
|
+
#### Scroll Detection Settings
|
|
604
|
+
Scroll events are detected with specific timing and distance thresholds to avoid excessive triggering. The default settings are:
|
|
605
|
+
|
|
606
|
+
- `scrollWait`: 50ms - Delay between scroll events
|
|
607
|
+
- `endScrollWait`: 400ms - Delay when scroll was stopped
|
|
608
|
+
- `minSpace`: 40px - Minimum distance between scroll events
|
|
609
|
+
|
|
610
|
+
These can be customized by setting scroll plugin options:
|
|
611
|
+
|
|
612
|
+
```js
|
|
613
|
+
short.enablePlugin ( pluginScroll, {
|
|
614
|
+
scrollWait: 100, // set delay to 100ms
|
|
615
|
+
endScrollWait: 600, // set end scroll delay to 600ms
|
|
616
|
+
minSpace: 60 // set minimum distance to 60px
|
|
617
|
+
})
|
|
618
|
+
```
|
|
619
|
+
|
|
620
|
+
#### Per-Context Setup (Preferred Method)
|
|
621
|
+
Instead of global plugin options, you can use `scroll:setup` event to configure plugin settings per context. This is preferred method for customization.
|
|
528
622
|
|
|
529
623
|
```js
|
|
530
624
|
const shortcutDefinition = {
|
|
531
|
-
|
|
532
|
-
'
|
|
533
|
-
//
|
|
625
|
+
sensitiveScrolling: {
|
|
626
|
+
'scroll:setup': ({ dependencies, defaults }) => {
|
|
627
|
+
// High sensitivity for gaming or precise interactions
|
|
534
628
|
return {
|
|
535
|
-
|
|
536
|
-
|
|
629
|
+
scrollWait: 20, // Very responsive
|
|
630
|
+
endScrollWait: 200, // Quick end detection
|
|
631
|
+
minSpace: 20 // Small movements trigger
|
|
537
632
|
};
|
|
538
633
|
},
|
|
539
|
-
'
|
|
540
|
-
'
|
|
634
|
+
'scroll:up': () => console.log('Sensitive scroll up'),
|
|
635
|
+
'scroll:down': () => console.log('Sensitive scroll down'),
|
|
636
|
+
'scroll:end': () => console.log('Sensitive scroll ended')
|
|
541
637
|
},
|
|
542
|
-
|
|
543
|
-
'
|
|
544
|
-
//
|
|
638
|
+
lazyScrolling: {
|
|
639
|
+
'scroll:setup': ({ dependencies, defaults }) => {
|
|
640
|
+
// Low sensitivity for reading or casual browsing
|
|
545
641
|
return {
|
|
546
|
-
|
|
547
|
-
|
|
642
|
+
scrollWait: 150, // Less responsive
|
|
643
|
+
endScrollWait: 800, // Slow end detection
|
|
644
|
+
minSpace: 80 // Larger movements needed
|
|
548
645
|
};
|
|
549
646
|
},
|
|
550
|
-
'
|
|
551
|
-
'
|
|
647
|
+
'scroll:up': () => console.log('Lazy scroll up'),
|
|
648
|
+
'scroll:down': () => console.log('Lazy scroll down'),
|
|
649
|
+
'scroll:end': () => console.log('Lazy scroll ended')
|
|
552
650
|
}
|
|
553
651
|
};
|
|
554
652
|
|
|
555
|
-
short.enablePlugin(
|
|
653
|
+
short.enablePlugin(pluginScroll);
|
|
556
654
|
short.load(shortcutDefinition);
|
|
557
|
-
short.changeContext('
|
|
558
|
-
// short.changeContext('
|
|
655
|
+
short.changeContext('sensitiveScrolling'); // Uses sensitive settings
|
|
656
|
+
// short.changeContext('lazyScrolling'); // Uses lazy settings
|
|
559
657
|
```
|
|
560
658
|
|
|
561
|
-
The `
|
|
659
|
+
The `scroll:setup` function receives:
|
|
562
660
|
- `dependencies` - External dependencies set via `setDependencies()`
|
|
563
661
|
- `defaults` - Default plugin options as a starting point
|
|
564
662
|
|
|
565
|
-
|
|
663
|
+
Example usage:
|
|
566
664
|
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
- '[' - open square bracket key
|
|
582
|
-
- ']' - close square bracket key
|
|
583
|
-
- '`' - backtick key
|
|
665
|
+
```js
|
|
666
|
+
const shortcutDefinition = {
|
|
667
|
+
scrollView: {
|
|
668
|
+
'scroll:up': () => {
|
|
669
|
+
console.log('User scrolled up');
|
|
670
|
+
},
|
|
671
|
+
'scroll:down': () => {
|
|
672
|
+
console.log('User scrolled down');
|
|
673
|
+
},
|
|
674
|
+
'scroll:end': () => {
|
|
675
|
+
console.log('User stopped scrolling');
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
};
|
|
584
679
|
|
|
585
|
-
|
|
680
|
+
short.enablePlugin(pluginScroll);
|
|
681
|
+
short.load(shortcutDefinition);
|
|
682
|
+
short.changeContext('scrollView');
|
|
683
|
+
```
|
|
586
684
|
|
|
587
|
-
|
|
685
|
+
Shortcuts context has `note` that works like sub-contexts. Every shortcut function receives a context and note as arguments, so you can have fine control over the context. See [Contexts, Notes, and Dependencies](#contexts-notes-and-dependencies).
|
|
588
686
|
|
|
589
687
|
|
|
590
688
|
|
|
689
|
+
### Plugin 'form' Shortcut Descriptions
|
|
591
690
|
|
|
691
|
+
`Form` plugin is used to watch for changes in inputs, textareas, select and textarea elements. All 3 possible shortcuts are predefined: `form: watch`, `form: define` and `form: action`.
|
|
592
692
|
|
|
593
|
-
## Plugin 'form' Shortcut Descriptions
|
|
594
|
-
`Form` plugin is used to watch for changes in inputs, textareas, select and textarea elements. All 3 possible shortcuts are predefined: 'form: watch', 'form: define' and 'form: action'.
|
|
595
693
|
```js
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
694
|
+
form: watch // (function). Should return list of elements to watch
|
|
695
|
+
form: define // (function). Define every element you are watching as a type (own definition)
|
|
696
|
+
form: action // (function). Must return a list of step objects. Each step has a fn, type, timing and optional wait
|
|
599
697
|
```
|
|
600
|
-
|
|
698
|
+
|
|
699
|
+
#### Action definition step shape
|
|
700
|
+
|
|
701
|
+
`form:action` returns an array of steps. Each step has four possible properties:
|
|
702
|
+
|
|
601
703
|
```js
|
|
602
704
|
{
|
|
603
|
-
fn
|
|
604
|
-
, type
|
|
605
|
-
, timing // (string)
|
|
606
|
-
, wait
|
|
705
|
+
fn // (function) Action function. Receives FormEventData.
|
|
706
|
+
, type // (string) Type of the element. Must match a value returned by `form: define`
|
|
707
|
+
, timing // (string) 'in' (focus in), 'out' (focus out), or 'instant' (value change)
|
|
708
|
+
, wait // (number) Event-reducer timer in ms. Only used when `timing: 'instant'`.
|
|
607
709
|
}
|
|
608
710
|
```
|
|
609
711
|
|
|
610
|
-
|
|
712
|
+
- `timing: 'in'` fires once when focus enters the element.
|
|
713
|
+
- `timing: 'out'` fires once when focus leaves the element.
|
|
714
|
+
- `timing: 'instant'` fires on each value change but is throttled by `wait` ms so the action doesn't run on every keystroke.
|
|
715
|
+
|
|
716
|
+
#### Definition example
|
|
717
|
+
|
|
611
718
|
```js
|
|
612
719
|
const shortcutScope = {
|
|
613
720
|
...
|
|
@@ -636,7 +743,7 @@ const shortcutScope = {
|
|
|
636
743
|
fn: () => { console.log ( 'Update content') }
|
|
637
744
|
, type : 'input'
|
|
638
745
|
, timing : 'instant' // on content change. on each change
|
|
639
|
-
, wait : 500 // Wait 500ms between changes.
|
|
746
|
+
, wait : 500 // Wait 500ms between changes.
|
|
640
747
|
},
|
|
641
748
|
{
|
|
642
749
|
fn: () => { console.log('It was a button') }
|
|
@@ -646,9 +753,13 @@ const shortcutScope = {
|
|
|
646
753
|
] // form: action
|
|
647
754
|
}
|
|
648
755
|
```
|
|
649
|
-
`form:watch` can contains `.someClass` for selecting elements by class name or `#someId` for selecting elements by id. It's could be everything that works in querySelectorAll. The `form:define` gives you a way to separate different inputs and privide a custom callback for each of them or use single callback for all inputs.
|
|
650
756
|
|
|
651
|
-
|
|
757
|
+
`form:watch` can contain `.someClass` for selecting elements by class name or `#someId` for selecting elements by id. It's could be everything that works in `querySelectorAll`. The `form:define` gives you a way to separate different inputs and privide a custom callback for each of them or use single callback for all inputs.
|
|
758
|
+
|
|
759
|
+
#### Default `form:watch` and `form:define`
|
|
760
|
+
|
|
761
|
+
The `form` plugin ships with defaults for `form:watch` and `form:define`. Only `form:action` is required.
|
|
762
|
+
|
|
652
763
|
```js
|
|
653
764
|
const _defaults = {
|
|
654
765
|
watch : () => 'input, select, textarea, button, a'
|
|
@@ -664,9 +775,18 @@ const _defaults = {
|
|
|
664
775
|
} // defaults
|
|
665
776
|
```
|
|
666
777
|
|
|
667
|
-
|
|
778
|
+
#### Pausing a specific form event
|
|
779
|
+
|
|
780
|
+
To pause or resume a single form event, call `short.pause(eventName)` / `short.resume(eventName)` where `eventName` is `${type}/${timing}`. Take `type` and `timing` from the action definitions.
|
|
781
|
+
|
|
782
|
+
```js
|
|
783
|
+
// Disable 'instant' updates on inputs
|
|
784
|
+
short.pause('input/instant');
|
|
785
|
+
// Re-enable them
|
|
786
|
+
short.resume('input/instant');
|
|
787
|
+
```
|
|
668
788
|
|
|
669
|
-
|
|
789
|
+
#### Per-Context Setup (Coming Soon)
|
|
670
790
|
The `form:setup` event is planned for future versions to allow per-context configuration of form plugin settings. Currently, form plugin uses default settings or global plugin options.
|
|
671
791
|
|
|
672
792
|
**Note**: In version 4.0.0, the `form:action` event now has access to `dependencies` at the top level, allowing you to minimize dependency declarations. Other named arguments are not available at the top level of `form:action`.
|
|
@@ -674,42 +794,89 @@ The `form:setup` event is planned for future versions to allow per-context confi
|
|
|
674
794
|
|
|
675
795
|
|
|
676
796
|
## Action Functions
|
|
797
|
+
|
|
677
798
|
Action functions are called when a shortcut is triggered. There is a difference among plugin action functions. Arguments are slightly different.
|
|
678
799
|
|
|
800
|
+
> Every action function `data` object also contains `emit` — a reference to the library's internal event emitter. See [Custom Events & Workflows](#custom-events--workflows).
|
|
801
|
+
|
|
679
802
|
|
|
680
803
|
|
|
681
804
|
### Keyboard Action Functions
|
|
682
|
-
|
|
805
|
+
|
|
806
|
+
The `key` plugin's `data` object includes helper functions to control sequences manually (useful when the timer-based detection is undesirable). Disable auto-detection by using a multi-key sequence, then call `wait`/`end` to control when it is allowed to match.
|
|
807
|
+
|
|
683
808
|
```js
|
|
684
809
|
function myKeyHandler ({
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
810
|
+
context // (string) Name of the current context;
|
|
811
|
+
, note // (string) Name of the note or null if note isn't set;
|
|
812
|
+
, dependencies // (object) Object with dependencies that you have set by calling `setDependencies` method;
|
|
813
|
+
, wait // (function). Stop the sequence timer and write the shortcut sequence without a timer. Use inside a key handler when you want manual control of the sequence.
|
|
814
|
+
, end // (function). Recover the sequence timer (the opposite of `wait`).
|
|
815
|
+
, ignore // (function). Ignore the current shortcut from the sequence. Useful for keys that should not advance the sequence (e.g. modifier keys).
|
|
816
|
+
, isWaiting // (boolean). True if the sequence timer is currently active.
|
|
817
|
+
, emit // (function). Call it to trigger a shortcut or custom event;
|
|
818
|
+
}) {
|
|
693
819
|
// Body of the handler. Do something...
|
|
694
820
|
}
|
|
695
821
|
```
|
|
696
822
|
|
|
697
823
|
|
|
698
824
|
|
|
699
|
-
|
|
700
825
|
### Mouse Action Functions
|
|
826
|
+
|
|
701
827
|
Click plugin action functions can be described like:
|
|
702
828
|
|
|
703
829
|
```js
|
|
704
830
|
function myMouseHandler ({
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
831
|
+
context // (string) Name of the current context;
|
|
832
|
+
, note // (string) Name of the note or null if note isn't set;
|
|
833
|
+
, dependencies // (object) Object with dependencies that you have set by calling `setDependencies` method;
|
|
834
|
+
, target // (DOM element). Target element of the mouse event;
|
|
835
|
+
, targetProps // (object). Coordinates of the target element (top, left, right, bottom, width, height) or null if target element is not available;
|
|
836
|
+
, x // (number). X coordinate of the target element;
|
|
837
|
+
, y // (number). Y coordinate of the target element;
|
|
838
|
+
, event // (object). Original mouse event object;
|
|
839
|
+
, emit // (function). Call it to trigger a shortcut or custom event;
|
|
840
|
+
}) {
|
|
841
|
+
// Body of the handler. Do something...
|
|
842
|
+
}
|
|
843
|
+
```
|
|
844
|
+
|
|
845
|
+
|
|
846
|
+
|
|
847
|
+
### Hover Action Functions
|
|
848
|
+
|
|
849
|
+
Hover plugin action functions receive the following arguments:
|
|
850
|
+
|
|
851
|
+
```js
|
|
852
|
+
function myHoverHandler ({
|
|
853
|
+
context // (string) Name of the current context;
|
|
854
|
+
, note // (string) Name of the note or null if note isn't set;
|
|
855
|
+
, dependencies // (object) Object with dependencies that you have set by calling `setDependencies` method;
|
|
856
|
+
, target // (DOM element). Target element of the hover event;
|
|
857
|
+
, targetProps // (object). Coordinates of the target element (top, left, right, bottom, width, height) or null if target element is not available;
|
|
858
|
+
, x // (number). X coordinate of the target element;
|
|
859
|
+
, y // (number). Y coordinate of the target element;
|
|
860
|
+
, event // (object). Original hover event object;
|
|
861
|
+
, emit // (function). Call it to trigger a shortcut or custom event;
|
|
862
|
+
}) {
|
|
863
|
+
// Body of the handler. Do something...
|
|
864
|
+
}
|
|
865
|
+
```
|
|
866
|
+
|
|
867
|
+
|
|
868
|
+
|
|
869
|
+
### Scroll Action Functions
|
|
870
|
+
|
|
871
|
+
Scroll plugin action functions receive the following arguments:
|
|
872
|
+
|
|
873
|
+
```js
|
|
874
|
+
function myScrollHandler ({
|
|
875
|
+
context // (string) Name of the current context;
|
|
876
|
+
, note // (string) Name of the note or null if note isn't set;
|
|
877
|
+
, dependencies // (object) Object with dependencies that you have set by calling `setDependencies` method;
|
|
878
|
+
, event // (object). Original scroll event object;
|
|
879
|
+
, emit // (function). Emit event to trigger a shortcut or custom event;
|
|
713
880
|
}) {
|
|
714
881
|
// Body of the handler. Do something...
|
|
715
882
|
}
|
|
@@ -717,137 +884,474 @@ function myMouseHandler ({
|
|
|
717
884
|
|
|
718
885
|
|
|
719
886
|
|
|
887
|
+
### Form Action Functions
|
|
888
|
+
|
|
889
|
+
The `fn` inside each `form:action` step receives the same shape as the other plugins, plus `target` and the type of change (`type`, `timing`):
|
|
890
|
+
|
|
891
|
+
```js
|
|
892
|
+
function myFormHandler ({
|
|
893
|
+
context // (string) Name of the current context;
|
|
894
|
+
, note // (string) Name of the note or null if note isn't set;
|
|
895
|
+
, dependencies // (object) Object with dependencies that you have set by calling `setDependencies` method;
|
|
896
|
+
, target // (DOM element). Element that triggered the form event;
|
|
897
|
+
, type // (string). The type label returned by 'form: define';
|
|
898
|
+
, timing // (string). 'in' | 'out' | 'instant';
|
|
899
|
+
, wait // (number). The reducer interval in ms (only when timing: 'instant');
|
|
900
|
+
, emit // (function). Call it to trigger a shortcut or custom event;
|
|
901
|
+
}) {
|
|
902
|
+
// Body of the handler. Do something...
|
|
903
|
+
}
|
|
904
|
+
```
|
|
905
|
+
|
|
906
|
+
> The `form:action` outer function itself receives `{ dependencies }` (and nothing else).
|
|
907
|
+
|
|
720
908
|
|
|
721
909
|
|
|
722
910
|
## Methods
|
|
723
911
|
|
|
724
|
-
|
|
912
|
+
Below is the full API of a `shortcuts()` instance. Every method is described with its signature, what it returns, and a usage example.
|
|
913
|
+
|
|
914
|
+
|
|
915
|
+
|
|
916
|
+
### `load(shortcutsUpdate)`
|
|
917
|
+
|
|
918
|
+
Load a context with shortcuts. Can be called multiple times to add or replace contexts.
|
|
919
|
+
|
|
920
|
+
- **Returns:** `void`
|
|
921
|
+
- **Emits errors:** none
|
|
725
922
|
|
|
726
923
|
```js
|
|
727
|
-
|
|
728
|
-
|
|
924
|
+
short.load({
|
|
925
|
+
editor: {
|
|
926
|
+
'key:ctrl+s': () => save(),
|
|
927
|
+
'click:left-1': ({ target }) => handleClick(target)
|
|
928
|
+
},
|
|
929
|
+
viewer: {
|
|
930
|
+
// ...
|
|
931
|
+
}
|
|
932
|
+
});
|
|
933
|
+
```
|
|
934
|
+
|
|
935
|
+
> If you `load` a context that is **currently active**, the library will re-apply it so the new shortcuts take effect immediately. No need to call `changeContext` again.
|
|
936
|
+
|
|
729
937
|
|
|
730
|
-
, enablePlugin : 'Enable a plugin.'
|
|
731
|
-
, disablePlugin : 'Disable a plugin.'
|
|
732
|
-
, mutePlugin : 'Mute a plugin. All events for the plugin will be ignored.'
|
|
733
|
-
, unmutePlugin : 'Unmute a plugin. All events for the plugin will be listened again.'
|
|
734
938
|
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
, reset : 'Reset shortcut instance.'
|
|
939
|
+
### `unload(contextName)`
|
|
940
|
+
|
|
941
|
+
Remove a context and all its shortcuts. Cannot remove the currently active context.
|
|
942
|
+
|
|
943
|
+
- **Returns:** `void`
|
|
944
|
+
- **Emits errors:**
|
|
945
|
+
- `'@shortcuts-error'` — if `contextName` is the active context (call `changeContext` first).
|
|
946
|
+
- `'@shortcuts-error'` — if `contextName` doesn't exist.
|
|
947
|
+
|
|
948
|
+
```js
|
|
949
|
+
short.changeContext('editor');
|
|
950
|
+
short.unload('login'); // removes 'login' and its shortcuts
|
|
748
951
|
```
|
|
749
952
|
|
|
750
|
-
|
|
751
|
-
|
|
953
|
+
|
|
954
|
+
|
|
955
|
+
### `enablePlugin(plugin, options?)` and `disablePlugin(pluginName)`
|
|
956
|
+
|
|
957
|
+
Enable a plugin. Calling with a plugin that is already enabled will replace it (useful for hot-reloading options). `disablePlugin` permanently removes the plugin — you'll need to call `enablePlugin` again to use it.
|
|
958
|
+
|
|
959
|
+
- **Returns:** `void`
|
|
960
|
+
- **Emits errors:** none
|
|
752
961
|
|
|
753
962
|
```js
|
|
754
|
-
//
|
|
755
|
-
short.
|
|
756
|
-
short.
|
|
963
|
+
short.enablePlugin(pluginKey); // enable with defaults
|
|
964
|
+
short.enablePlugin(pluginKey, { keyWait: 300 }); // enable with custom options
|
|
965
|
+
short.disablePlugin('key'); // permanently disable
|
|
966
|
+
```
|
|
967
|
+
|
|
968
|
+
> Pass the **plugin function** to `enablePlugin`, but the plugin's **prefix string** to `disablePlugin` (the value returned by `listPlugins()`).
|
|
969
|
+
|
|
970
|
+
|
|
757
971
|
|
|
758
|
-
|
|
972
|
+
### `mutePlugin(pluginName)` and `unmutePlugin(pluginName)`
|
|
973
|
+
|
|
974
|
+
Temporarily suspend / resume a plugin. Muted plugins keep their state but stop processing events. Use these for "soft" disable (e.g. when a modal opens) — they are reversible.
|
|
975
|
+
|
|
976
|
+
- **Returns:** `number` — index of the plugin in the internal array, or `-1` if not found.
|
|
977
|
+
- **Emits errors:** none
|
|
978
|
+
|
|
979
|
+
```js
|
|
980
|
+
short.mutePlugin('key'); // ignore all keyboard shortcuts
|
|
981
|
+
short.unmutePlugin('key'); // resume keyboard shortcuts
|
|
759
982
|
```
|
|
760
983
|
|
|
984
|
+
> **`mutePlugin` vs `disablePlugin`** — `disablePlugin` destroys the plugin (you'll lose any per-context setup state). `mutePlugin` keeps the plugin registered and just stops it from processing events. Prefer `mutePlugin` for transient pauses.
|
|
761
985
|
|
|
762
986
|
|
|
763
|
-
## Options
|
|
764
987
|
|
|
765
|
-
|
|
988
|
+
### `changeContext(contextName?)`
|
|
989
|
+
|
|
990
|
+
Switch to a different context. Pass `null`, `undefined`, or no argument to **deactivate** the current context (no shortcuts fire).
|
|
991
|
+
|
|
992
|
+
- **Returns:** `void`
|
|
993
|
+
- **Emits errors:**
|
|
994
|
+
- `'@shortcuts-error'` — if `contextName` doesn't exist.
|
|
766
995
|
|
|
767
996
|
```js
|
|
768
|
-
|
|
997
|
+
short.changeContext('editor'); // switch to 'editor'
|
|
998
|
+
short.changeContext(); // deactivate all shortcuts
|
|
769
999
|
```
|
|
1000
|
+
|
|
1001
|
+
|
|
1002
|
+
|
|
1003
|
+
### `getContext()`
|
|
1004
|
+
|
|
1005
|
+
Return the name of the currently active context, or `null` if none.
|
|
1006
|
+
|
|
1007
|
+
- **Returns:** `string | null`
|
|
1008
|
+
|
|
770
1009
|
```js
|
|
771
|
-
|
|
1010
|
+
if (short.getContext() === 'editor') {
|
|
1011
|
+
// editor-specific UI logic
|
|
1012
|
+
}
|
|
772
1013
|
```
|
|
773
1014
|
|
|
774
1015
|
|
|
775
1016
|
|
|
776
|
-
###
|
|
1017
|
+
### `getNote()` and `setNote(note?)`
|
|
1018
|
+
|
|
1019
|
+
`setNote` tags the current context with a sub-context string. `getNote` reads it back. Pass `null` / no argument to `setNote` to clear it. Non-string arguments are silently ignored.
|
|
1020
|
+
|
|
1021
|
+
- **Returns:** `getNote` returns `string | null`; `setNote` returns `void`.
|
|
1022
|
+
- **Emits errors:** none
|
|
1023
|
+
|
|
777
1024
|
```js
|
|
778
|
-
|
|
779
|
-
|
|
1025
|
+
short.setNote('special'); // tag the current context
|
|
1026
|
+
short.getNote(); // 'special'
|
|
1027
|
+
short.setNote(); // clear the note (passing nothing)
|
|
1028
|
+
short.setNote(null); // same — explicit null
|
|
1029
|
+
|
|
1030
|
+
// Inside an action function:
|
|
1031
|
+
'key:ctrl+s': ({ note }) => {
|
|
1032
|
+
if (note === 'special') {
|
|
1033
|
+
// do the "special" variant of save
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
780
1036
|
```
|
|
781
1037
|
|
|
1038
|
+
The idea of `note` is to minimize the number of contexts if they are very similar — keep one context, switch its `note`, and branch inside the action by reading it.
|
|
782
1039
|
|
|
783
1040
|
|
|
784
|
-
|
|
1041
|
+
|
|
1042
|
+
### `setDependencies(deps)` and `getDependencies()`
|
|
1043
|
+
|
|
1044
|
+
`setDependencies` registers a bag of external values that will be merged into the `dependencies` object passed to every action function. `getDependencies` returns the live bag (mutating it affects future shortcut calls — `setDependencies` is `Object.assign`-based, not a snapshot).
|
|
1045
|
+
|
|
1046
|
+
- **Returns:** `getDependencies` returns `object`; `setDependencies` returns `void`.
|
|
1047
|
+
- **Emits errors:** none
|
|
1048
|
+
|
|
785
1049
|
```js
|
|
786
|
-
|
|
787
|
-
|
|
1050
|
+
// Once at startup:
|
|
1051
|
+
short.setDependencies({
|
|
1052
|
+
api: myApi,
|
|
1053
|
+
router: myRouter,
|
|
1054
|
+
analytics: track
|
|
1055
|
+
});
|
|
1056
|
+
|
|
1057
|
+
// Inside any action function:
|
|
1058
|
+
'key:ctrl+s': ({ dependencies }) => {
|
|
1059
|
+
dependencies.api.save();
|
|
1060
|
+
dependencies.analytics.track('save');
|
|
1061
|
+
}
|
|
788
1062
|
```
|
|
789
1063
|
|
|
790
|
-
|
|
1064
|
+
> `dependencies` is also available inside `form:action`, `key:setup`, `click:setup`, `hover:setup`, `scroll:setup`, `onShortcut`, and `streamKeys` — anywhere the library hands you a `data` object.
|
|
1065
|
+
|
|
1066
|
+
|
|
1067
|
+
|
|
1068
|
+
### `listPlugins()`
|
|
1069
|
+
|
|
1070
|
+
Return an array of enabled plugin prefixes.
|
|
1071
|
+
|
|
1072
|
+
- **Returns:** `string[]` (e.g. `['key', 'click']`)
|
|
1073
|
+
|
|
791
1074
|
```js
|
|
792
|
-
|
|
793
|
-
, hoverTarget : 'Array of attribute names to recognize hover items in HTML. Default value - ["data-hover"]' // checks for data-hover='someName' attribute
|
|
1075
|
+
short.listPlugins(); // ['key', 'click', 'hover']
|
|
794
1076
|
```
|
|
795
1077
|
|
|
796
|
-
|
|
1078
|
+
|
|
1079
|
+
|
|
1080
|
+
### `listContexts()`
|
|
1081
|
+
|
|
1082
|
+
Return an array of all loaded context names (including the inactive ones).
|
|
1083
|
+
|
|
1084
|
+
- **Returns:** `string[]`
|
|
1085
|
+
|
|
797
1086
|
```js
|
|
798
|
-
|
|
799
|
-
, endScrollWait : 'Delay when scroll was stopped in ms. Default value - 400.'
|
|
800
|
-
, minSpace : 'Minimum distance between scroll events in px. Default value - 40.'
|
|
1087
|
+
short.listContexts(); // ['login', 'editor', 'settings']
|
|
801
1088
|
```
|
|
802
1089
|
|
|
803
|
-
|
|
804
|
-
|
|
1090
|
+
|
|
1091
|
+
|
|
1092
|
+
### `listShortcuts(contextName?)`
|
|
1093
|
+
|
|
1094
|
+
Return a list of shortcuts. Two return shapes:
|
|
1095
|
+
|
|
1096
|
+
- With no argument — an array of `{ context, shortcuts }` for every context.
|
|
1097
|
+
- With a context name — an array of shortcut names for that context, or `null` if the context doesn't exist.
|
|
1098
|
+
|
|
1099
|
+
- **Returns:** `string[] | { context: string, shortcuts: string[] }[] | null`
|
|
1100
|
+
|
|
805
1101
|
```js
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
1102
|
+
short.listShortcuts();
|
|
1103
|
+
// [
|
|
1104
|
+
// { context: 'editor', shortcuts: ['KEY:CTRL+S', 'CLICK:LEFT-1', ...] },
|
|
1105
|
+
// { context: 'viewer', shortcuts: ['KEY:ESC'] }
|
|
1106
|
+
// ]
|
|
810
1107
|
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
, clickTarget: ['data-puk', 'data-button'] // array of attribute names to check
|
|
814
|
-
})
|
|
1108
|
+
short.listShortcuts('editor');
|
|
1109
|
+
// ['KEY:CTRL+S', 'CLICK:LEFT-1']
|
|
815
1110
|
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
, hoverTarget: ['data-hover-me', 'data-interactive'] // array of attribute names to check
|
|
819
|
-
})
|
|
1111
|
+
short.listShortcuts('does-not-exist'); // null
|
|
1112
|
+
```
|
|
820
1113
|
|
|
821
|
-
short.enablePlugin ( pluginScroll, {
|
|
822
|
-
scrollWait: 100 // set the delay between scroll events to 100ms
|
|
823
|
-
, endScrollWait: 600 // set the end scroll delay to 600ms
|
|
824
|
-
, minSpace: 60 // set minimum distance to 60px
|
|
825
|
-
})
|
|
826
1114
|
|
|
1115
|
+
|
|
1116
|
+
### `pause(name?)` and `resume(name?)`
|
|
1117
|
+
|
|
1118
|
+
Stop / resume listening for shortcuts. Both default to `'*'` (all shortcuts in the active context). The `name` must be a **fully-prefixed** shortcut name (e.g. `'KEY:CTRL+S'`, not `'ctrl+s'`).
|
|
1119
|
+
|
|
1120
|
+
- **Returns:** `void`
|
|
1121
|
+
- **Emits errors:** none
|
|
1122
|
+
- **Side effect:** an in-flight key sequence is dropped on `pause`, not queued for resume.
|
|
1123
|
+
|
|
1124
|
+
```js
|
|
1125
|
+
short.pause(); // pause all shortcuts in the active context
|
|
1126
|
+
short.pause('KEY:CTRL+S'); // pause just one shortcut (use the full prefix!)
|
|
1127
|
+
short.resume('KEY:CTRL+S'); // resume just that one
|
|
1128
|
+
short.resume('*'); // resume everything
|
|
1129
|
+
```
|
|
1130
|
+
|
|
1131
|
+
|
|
1132
|
+
|
|
1133
|
+
### `emit(name, ...args)`
|
|
1134
|
+
|
|
1135
|
+
Programmatically trigger a shortcut or a custom event. The first argument is the **fully-prefixed** shortcut name (or any custom event string you define — see [Custom Events & Workflows](#custom-events--workflows)). Extra arguments are forwarded to the action function.
|
|
1136
|
+
|
|
1137
|
+
- **Returns:** `void`
|
|
1138
|
+
- **Emits errors:** none
|
|
1139
|
+
|
|
1140
|
+
```js
|
|
1141
|
+
short.emit('KEY:CTRL+S'); // fire the save shortcut
|
|
1142
|
+
short.emit('CLICK:LEFT-1', myTarget); // forward a synthetic click
|
|
1143
|
+
short.emit('@extend', { source: 'api' }); // fire a custom event
|
|
1144
|
+
```
|
|
1145
|
+
|
|
1146
|
+
See the [Custom Events & Workflows](#custom-events--workflows) section for full examples of `emit` from inside a handler (`data.dependencies.emit(...)`) and from outside (`short.emit(...)`).
|
|
1147
|
+
|
|
1148
|
+
|
|
1149
|
+
|
|
1150
|
+
### `reset()`
|
|
1151
|
+
|
|
1152
|
+
Reset the library instance to its initial state. Destroys every enabled plugin, unloads every context, deactivates the current context, and clears the `dependencies` bag. After `reset()`, you can re-`enablePlugin` and re-`load` from scratch.
|
|
1153
|
+
|
|
1154
|
+
- **Returns:** `void`
|
|
1155
|
+
- **Emits errors:** none
|
|
1156
|
+
- **Side effects:** `onShortcut` callback is cleared. `errorEventName` is preserved.
|
|
1157
|
+
|
|
1158
|
+
```js
|
|
1159
|
+
short.reset();
|
|
1160
|
+
// short is now equivalent to a freshly created `shortcuts()` instance
|
|
1161
|
+
```
|
|
1162
|
+
|
|
1163
|
+
|
|
1164
|
+
|
|
1165
|
+
## Contexts, Notes, and Dependencies
|
|
1166
|
+
|
|
1167
|
+
The three orthogonal axes you control from outside the action functions:
|
|
1168
|
+
|
|
1169
|
+
- **Context** — which set of shortcuts is active. Use `changeContext` to switch.
|
|
1170
|
+
- **Note** — a sub-tag for the current context. Use `setNote` to set, `getNote` to read.
|
|
1171
|
+
- **Dependencies** — external services passed into actions. Use `setDependencies` to register, available as `dependencies` in every action.
|
|
1172
|
+
|
|
1173
|
+
```js
|
|
1174
|
+
short.setDependencies({ api, router });
|
|
1175
|
+
short.changeContext('editor');
|
|
1176
|
+
short.setNote('draft');
|
|
1177
|
+
|
|
1178
|
+
'key:ctrl+s': ({ context, note, dependencies }) => {
|
|
1179
|
+
// context === 'editor'
|
|
1180
|
+
// note === 'draft'
|
|
1181
|
+
// dependencies === { api, router }
|
|
1182
|
+
dependencies.api.save({ context, note });
|
|
1183
|
+
}
|
|
1184
|
+
```
|
|
1185
|
+
|
|
1186
|
+
Read each value from outside the actions with `getContext()`, `getNote()`, `getDependencies()`. Set them with `changeContext()`, `setNote()`, `setDependencies()`.
|
|
1187
|
+
|
|
1188
|
+
|
|
1189
|
+
|
|
1190
|
+
## Errors and the `errorEventName` Channel
|
|
1191
|
+
|
|
1192
|
+
The library publishes error messages on a single named event instead of throwing. By default that event is named `'@shortcuts-error'`. You can rename it with the `errorEventName` constructor option (see [Constructor Options](#constructor-options)).
|
|
1193
|
+
|
|
1194
|
+
Errors currently emitted:
|
|
1195
|
+
- `changeContext(name)` — `name` does not exist.
|
|
1196
|
+
- `unload(name)` — `name` is the currently active context.
|
|
1197
|
+
- `unload(name)` — `name` does not exist.
|
|
1198
|
+
|
|
1199
|
+
The message is delivered as the **first argument** to the listener. Because the library uses the [`@peter.naydenov/notice`](https://github.com/PeterNaydenov/notice) event emitter internally, the simplest way to subscribe is to install a listener via the public `emit` channel — but the cleanest way is to handle errors inside your own action handlers (e.g. wrap risky work in `try/catch`).
|
|
1200
|
+
|
|
1201
|
+
```js
|
|
1202
|
+
const short = shortcuts({ errorEventName: '@my-app-errors' });
|
|
1203
|
+
|
|
1204
|
+
// Optional: forward errors anywhere you like. The library exposes
|
|
1205
|
+
// the event emitter indirectly through the action context:
|
|
1206
|
+
// If you need a programmatic hook, expose it via setDependencies:
|
|
1207
|
+
// short.setDependencies({
|
|
1208
|
+
// onError: (msg) => myLogger.error(msg)
|
|
1209
|
+
// });
|
|
1210
|
+
//
|
|
1211
|
+
// Then in any handler that can fail:
|
|
1212
|
+
// 'key:ctrl+s': ({ dependencies }) => {
|
|
1213
|
+
// try { save() }
|
|
1214
|
+
// catch (e) { dependencies.onError(`Save failed: ${e.message}`) }
|
|
1215
|
+
// }
|
|
1216
|
+
```
|
|
1217
|
+
|
|
1218
|
+
> If you don't need to react to errors at runtime, you can simply ignore this channel — errors are advisory, not fatal.
|
|
1219
|
+
|
|
1220
|
+
|
|
1221
|
+
|
|
1222
|
+
## Custom Events & Workflows
|
|
1223
|
+
|
|
1224
|
+
Every plugin callback receives a `data` object that includes a `dependencies` bag with an `emit` function — the same event emitter used internally by the library. This lets a handler trigger any other event in the system, so you can build pipelines where one signal chains into another.
|
|
1225
|
+
|
|
1226
|
+
### The `data.dependencies.emit` property
|
|
1227
|
+
|
|
1228
|
+
The `data` argument passed to your callback contains:
|
|
1229
|
+
|
|
1230
|
+
```js
|
|
1231
|
+
{
|
|
1232
|
+
// ... event-specific fields (target, key, context, type, etc.)
|
|
1233
|
+
dependencies: {
|
|
1234
|
+
// `emit` is always present — it's the library's event emitter.
|
|
1235
|
+
emit: ev.emit, // function(eventName, ...args)
|
|
1236
|
+
// ... any other keys you set via short.setDependencies({...})
|
|
1237
|
+
}
|
|
1238
|
+
}
|
|
1239
|
+
```
|
|
1240
|
+
|
|
1241
|
+
`data.dependencies.emit` is a direct reference to the underlying event emitter. Calling it triggers the named event just like `shortcuts.emit(...)` does, but from inside a handler. Any extra values you pass to `short.setDependencies({...})` are merged into this same bag, so a single `data.dependencies` field carries both your application data and the `emit` function.
|
|
1242
|
+
|
|
1243
|
+
### Example: chaining a key shortcut into a click
|
|
1244
|
+
|
|
1245
|
+
```js
|
|
1246
|
+
import { shortcuts, pluginKey, pluginClick } from '@peter.naydenov/shortcuts';
|
|
1247
|
+
|
|
1248
|
+
const short = shortcuts();
|
|
1249
|
+
short.enablePlugin(pluginKey);
|
|
1250
|
+
short.enablePlugin(pluginClick);
|
|
1251
|
+
|
|
1252
|
+
short.load({
|
|
1253
|
+
editor: {
|
|
1254
|
+
'key: ctrl+s': (data) => {
|
|
1255
|
+
console.log('Save requested');
|
|
1256
|
+
|
|
1257
|
+
// Trigger a click event on something — for example, a "Save" button
|
|
1258
|
+
data.dependencies.emit('CLICK:LEFT-1', { target: document.getElementById('save-btn') });
|
|
1259
|
+
},
|
|
1260
|
+
'click: left-1': ({ target }) => {
|
|
1261
|
+
if (target?.id === 'save-btn') {
|
|
1262
|
+
console.log('Save button clicked by Ctrl+S');
|
|
1263
|
+
doSave();
|
|
1264
|
+
}
|
|
1265
|
+
}
|
|
1266
|
+
}
|
|
1267
|
+
});
|
|
1268
|
+
|
|
1269
|
+
short.changeContext('editor');
|
|
827
1270
|
```
|
|
828
1271
|
|
|
1272
|
+
### Example: workflow with multiple plugins
|
|
829
1273
|
|
|
1274
|
+
You can mix signals from different plugins in a single workflow:
|
|
830
1275
|
|
|
831
|
-
### onShortcut option
|
|
832
1276
|
```js
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
1277
|
+
short.load({
|
|
1278
|
+
main: {
|
|
1279
|
+
'hover : on': (data) => {
|
|
1280
|
+
// show tooltip
|
|
1281
|
+
showTooltip(data.target);
|
|
1282
|
+
},
|
|
1283
|
+
'key: escape': (data) => {
|
|
1284
|
+
// hide any open tooltip by emitting the hover-off signal
|
|
1285
|
+
data.dependencies.emit('HOVER:OFF');
|
|
1286
|
+
}
|
|
838
1287
|
}
|
|
1288
|
+
});
|
|
839
1289
|
```
|
|
840
1290
|
|
|
1291
|
+
### Notes
|
|
1292
|
+
|
|
1293
|
+
- The `emit` function lives on `data.dependencies` for every plugin (`key`, `click`, `hover`, `scroll`, `form`);
|
|
1294
|
+
- The event name passed to `emit` can be either a fully normalized plugin shortcut (e.g. `KEY:CTRL+S`, `CLICK:LEFT-1`, `SCROLL:DOWN`, `HOVER:ON`, `HOVER:OFF`) or a custom name you define. For form actions, use the `type/timing` key (e.g. `input/in`). See the [Custom Event Names](#custom-event-names-application-level-hooks) section below.
|
|
1295
|
+
- This is a *signal source*: any handler in the active context listening for the emitted event will run, including handlers attached to a different plugin. This makes it the foundation for pipelines and multi-step workflows.
|
|
1296
|
+
|
|
841
1297
|
|
|
842
1298
|
|
|
843
|
-
###
|
|
1299
|
+
### Custom Event Names (Application-Level Hooks)
|
|
1300
|
+
|
|
1301
|
+
The event name you pass to `data.dependencies.emit` does not have to be a plugin shortcut. It can be **any string you invent** — this lets you turn a physical gesture (click, hover, scroll, key) into a custom application signal. Other code, plugins, or modules can listen for that name and react.
|
|
1302
|
+
|
|
1303
|
+
Use a prefix that won't collide with plugin shortcuts (e.g. `@`, `app:`, `domain:`):
|
|
1304
|
+
|
|
844
1305
|
```js
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
1306
|
+
import { shortcuts, pluginClick, pluginHover } from '@peter.naydenov/shortcuts';
|
|
1307
|
+
|
|
1308
|
+
const short = shortcuts();
|
|
1309
|
+
short.enablePlugin(pluginClick);
|
|
1310
|
+
short.enablePlugin(pluginHover);
|
|
1311
|
+
|
|
1312
|
+
short.load({
|
|
1313
|
+
editor: {
|
|
1314
|
+
// A click anywhere in the editor area triggers the custom "@extend" event.
|
|
1315
|
+
// No keyboard shortcut is involved — only the click.
|
|
1316
|
+
'click: left-1': (data) => {
|
|
1317
|
+
// Forward the click as a custom application event.
|
|
1318
|
+
data.dependencies.emit('@extend', {
|
|
1319
|
+
target : data.target,
|
|
1320
|
+
at : { x: data.x, y: data.y },
|
|
1321
|
+
when : Date.now()
|
|
1322
|
+
});
|
|
1323
|
+
},
|
|
1324
|
+
|
|
1325
|
+
// A custom handler listens for "@extend" — this is NOT a plugin shortcut.
|
|
1326
|
+
// It is a hook that other parts of your app can subscribe to.
|
|
1327
|
+
'@extend': ({ target, at, when }) => {
|
|
1328
|
+
console.log('extend requested at', at, 'on', target);
|
|
1329
|
+
doExtend({ target, at, when });
|
|
1330
|
+
},
|
|
1331
|
+
|
|
1332
|
+
// Hover signals also work — you can wire the same hook to multiple gestures:
|
|
1333
|
+
'hover : on': (data) => {
|
|
1334
|
+
data.dependencies.emit('@extend', { target: data.target, source: 'hover' });
|
|
1335
|
+
}
|
|
850
1336
|
}
|
|
1337
|
+
});
|
|
1338
|
+
|
|
1339
|
+
short.changeContext('editor');
|
|
1340
|
+
```
|
|
1341
|
+
|
|
1342
|
+
**Why this is useful:**
|
|
1343
|
+
|
|
1344
|
+
- **Decoupling** — the gesture layer (click/hover/key) is separate from the application logic (`@extend`). You can change which gesture triggers it without touching the handler.
|
|
1345
|
+
- **Multiple gestures, one hook** — bind `@extend` to clicks, hovers, key combos, or even `shortcuts.emit('@extend')` from anywhere in your code.
|
|
1346
|
+
- **No collision with plugin events** — using a non-plugin prefix (`@`, `app:`, etc.) keeps your custom names from ever being emitted by the library itself.
|
|
1347
|
+
|
|
1348
|
+
You can also trigger a custom event from **outside** any handler using the public API:
|
|
1349
|
+
|
|
1350
|
+
```js
|
|
1351
|
+
// Trigger a custom event programmatically — no plugin involved
|
|
1352
|
+
shortcuts.emit('@extend', { source: 'api' });
|
|
1353
|
+
// or, if you have a short instance:
|
|
1354
|
+
short.emit('@extend', { source: 'api' });
|
|
851
1355
|
```
|
|
852
1356
|
|
|
853
1357
|
|
|
@@ -882,19 +1386,24 @@ short.changeContext('myContext');
|
|
|
882
1386
|
|
|
883
1387
|
The `ShortcutsAPI` interface provides full type safety for all methods and their parameters.
|
|
884
1388
|
|
|
1389
|
+
|
|
1390
|
+
|
|
885
1391
|
## Links
|
|
886
1392
|
|
|
887
1393
|
- [API reference](https://github.com/PeterNaydenov/shortcuts/blob/main/API.md)
|
|
888
|
-
- [How to make a plugin](https://github.com/PeterNaydenov/shortcuts/blob/main/How
|
|
889
|
-
- [
|
|
1394
|
+
- [How to make a plugin](https://github.com/PeterNaydenov/shortcuts/blob/main/How-to-create-a-plugin.md)
|
|
1395
|
+
- [Build a SPA apps with shortcuts (@peter.naydenov/cuts)](https://github.com/PeterNaydenov/cuts )
|
|
890
1396
|
- [History of changes - changelog](https://github.com/PeterNaydenov/shortcuts/blob/main/Changelog.md)
|
|
891
1397
|
- [Migration guide](https://github.com/PeterNaydenov/shortcuts/blob/main/Migration.guide.md)
|
|
892
1398
|
|
|
893
1399
|
|
|
1400
|
+
|
|
894
1401
|
## Credits
|
|
1402
|
+
|
|
895
1403
|
'@peter.naydenov/shortcuts' was created and supported by Peter Naydenov.
|
|
896
1404
|
|
|
897
1405
|
|
|
898
1406
|
|
|
899
1407
|
## License
|
|
900
|
-
|
|
1408
|
+
|
|
1409
|
+
'@peter.naydenov/shortcuts' is released under the MIT License.
|