@peter.naydenov/shortcuts 3.5.2 → 4.0.1

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.
Files changed (135) hide show
  1. package/API.md +939 -0
  2. package/CODE_OF_CONDUCT.md +84 -0
  3. package/CONTRIBUTING.md +476 -0
  4. package/Changelog.md +32 -2
  5. package/How.to.create.plugins.md +929 -0
  6. package/Migration.guide.md +48 -0
  7. package/README.md +396 -24
  8. package/dist/main.d.ts +54 -2
  9. package/dist/methods/_normalizeWithPlugins.d.ts +63 -1
  10. package/dist/methods/_readShortcutWithPlugins.d.ts +8 -1
  11. package/dist/methods/_setupPlugin.d.ts +9 -0
  12. package/dist/methods/_systemAction.d.ts +8 -1
  13. package/dist/methods/changeContext.d.ts +8 -1
  14. package/dist/methods/index.d.ts +2 -0
  15. package/dist/methods/listShortcuts.d.ts +1 -16
  16. package/dist/methods/load.d.ts +8 -1
  17. package/dist/methods/unload.d.ts +8 -1
  18. package/dist/plugins/click/_findTarget.d.ts +9 -1
  19. package/dist/plugins/click/_listenDOM.d.ts +76 -3
  20. package/dist/plugins/click/_normalizeShortcutName.d.ts +7 -1
  21. package/dist/plugins/click/_registerShortcutEvents.d.ts +26 -0
  22. package/dist/plugins/click/index.d.ts +6 -31
  23. package/dist/plugins/form/_defaults.d.ts +13 -1
  24. package/dist/plugins/form/_listenDOM.d.ts +66 -3
  25. package/dist/plugins/form/_registerShortcutEvents.d.ts +95 -1
  26. package/dist/plugins/form/index.d.ts +2 -29
  27. package/dist/plugins/hover/_findTarget.d.ts +10 -0
  28. package/dist/plugins/hover/_listenDOM.d.ts +68 -0
  29. package/dist/plugins/hover/_normalizeShortcutName.d.ts +2 -0
  30. package/dist/plugins/hover/_registerShortcutEvents.d.ts +28 -0
  31. package/dist/plugins/hover/index.d.ts +14 -0
  32. package/dist/plugins/key/_listenDOM.d.ts +61 -3
  33. package/dist/plugins/key/_registerShortcutEvents.d.ts +26 -0
  34. package/dist/plugins/key/_specialChars.d.ts +6 -31
  35. package/dist/plugins/key/index.d.ts +2 -29
  36. package/dist/plugins/scroll/_listenDOM.d.ts +58 -0
  37. package/dist/plugins/scroll/_normalizeShortcutName.d.ts +2 -0
  38. package/dist/plugins/scroll/_registerShortcutEvents.d.ts +28 -0
  39. package/dist/plugins/scroll/index.d.ts +16 -0
  40. package/dist/shortcuts.cjs +1 -1
  41. package/dist/shortcuts.esm.mjs +1 -1
  42. package/dist/shortcuts.umd.js +1 -1
  43. package/dist/src/main.d.ts +172 -0
  44. package/dist/src/methods/_normalizeWithPlugins.d.ts +64 -0
  45. package/dist/src/methods/_readShortcutWithPlugins.d.ts +9 -0
  46. package/dist/src/methods/_setupPlugin.d.ts +9 -0
  47. package/dist/src/methods/_systemAction.d.ts +9 -0
  48. package/dist/src/methods/changeContext.d.ts +9 -0
  49. package/dist/src/methods/index.d.ts +19 -0
  50. package/dist/src/methods/listShortcuts.d.ts +2 -0
  51. package/dist/src/methods/load.d.ts +9 -0
  52. package/dist/src/methods/unload.d.ts +9 -0
  53. package/dist/src/plugins/click/_findTarget.d.ts +10 -0
  54. package/dist/src/plugins/click/_listenDOM.d.ts +78 -0
  55. package/dist/src/plugins/click/_normalizeShortcutName.d.ts +8 -0
  56. package/dist/src/plugins/click/_readClickEvent.d.ts +2 -0
  57. package/dist/src/plugins/click/_registerShortcutEvents.d.ts +28 -0
  58. package/dist/src/plugins/click/index.d.ts +16 -0
  59. package/dist/src/plugins/form/_defaults.d.ts +17 -0
  60. package/dist/src/plugins/form/_listenDOM.d.ts +68 -0
  61. package/dist/src/plugins/form/_normalizeShortcutName.d.ts +2 -0
  62. package/dist/src/plugins/form/_registerShortcutEvents.d.ts +96 -0
  63. package/dist/src/plugins/form/index.d.ts +9 -0
  64. package/dist/src/plugins/hover/_findTarget.d.ts +10 -0
  65. package/dist/src/plugins/hover/_listenDOM.d.ts +68 -0
  66. package/dist/src/plugins/hover/_normalizeShortcutName.d.ts +2 -0
  67. package/dist/src/plugins/hover/_registerShortcutEvents.d.ts +28 -0
  68. package/dist/src/plugins/hover/index.d.ts +14 -0
  69. package/dist/src/plugins/key/_listenDOM.d.ts +63 -0
  70. package/dist/src/plugins/key/_normalizeShortcutName.d.ts +2 -0
  71. package/dist/src/plugins/key/_readKeyEvent.d.ts +2 -0
  72. package/dist/src/plugins/key/_registerShortcutEvents.d.ts +28 -0
  73. package/dist/src/plugins/key/_specialChars.d.ts +7 -0
  74. package/dist/src/plugins/key/index.d.ts +14 -0
  75. package/dist/src/plugins/scroll/_listenDOM.d.ts +58 -0
  76. package/dist/src/plugins/scroll/_normalizeShortcutName.d.ts +2 -0
  77. package/dist/src/plugins/scroll/_registerShortcutEvents.d.ts +28 -0
  78. package/dist/src/plugins/scroll/index.d.ts +16 -0
  79. package/eslint.config.js +80 -0
  80. package/html/assets/index-COTh6lXR.css +1 -0
  81. package/html/assets/index-DOkKC3NI.js +53 -0
  82. package/html/bg.png +0 -0
  83. package/html/favicon.ico +0 -0
  84. package/html/favicon.svg +5 -0
  85. package/html/html.meta.json.gz +0 -0
  86. package/html/index.html +32 -0
  87. package/package.json +24 -19
  88. package/shortcuts.png +0 -0
  89. package/src/main.js +52 -22
  90. package/src/methods/_normalizeWithPlugins.js +26 -2
  91. package/src/methods/_readShortcutWithPlugins.js +9 -2
  92. package/src/methods/_setupPlugin.js +93 -0
  93. package/src/methods/_systemAction.js +12 -4
  94. package/src/methods/changeContext.js +11 -3
  95. package/src/methods/index.js +2 -0
  96. package/src/methods/listShortcuts.js +5 -12
  97. package/src/methods/load.js +11 -4
  98. package/src/methods/unload.js +8 -1
  99. package/src/plugins/click/_findTarget.js +11 -5
  100. package/src/plugins/click/_listenDOM.js +58 -20
  101. package/src/plugins/click/_normalizeShortcutName.js +11 -4
  102. package/src/plugins/click/_readClickEvent.js +1 -1
  103. package/src/plugins/click/_registerShortcutEvents.js +33 -5
  104. package/src/plugins/click/index.js +33 -60
  105. package/src/plugins/form/_defaults.js +13 -3
  106. package/src/plugins/form/_listenDOM.js +46 -9
  107. package/src/plugins/form/_normalizeShortcutName.js +2 -2
  108. package/src/plugins/form/_registerShortcutEvents.js +93 -17
  109. package/src/plugins/form/index.js +25 -56
  110. package/src/plugins/hover/_findTarget.js +26 -0
  111. package/src/plugins/hover/_listenDOM.js +154 -0
  112. package/src/plugins/hover/_normalizeShortcutName.js +21 -0
  113. package/src/plugins/hover/_registerShortcutEvents.js +51 -0
  114. package/src/plugins/hover/index.js +71 -0
  115. package/src/plugins/key/_listenDOM.js +67 -33
  116. package/src/plugins/key/_normalizeShortcutName.js +4 -3
  117. package/src/plugins/key/_readKeyEvent.js +1 -1
  118. package/src/plugins/key/_registerShortcutEvents.js +34 -5
  119. package/src/plugins/key/_specialChars.js +5 -0
  120. package/src/plugins/key/index.js +34 -59
  121. package/src/plugins/scroll/_listenDOM.js +141 -0
  122. package/src/plugins/scroll/_normalizeShortcutName.js +21 -0
  123. package/src/plugins/scroll/_registerShortcutEvents.js +50 -0
  124. package/src/plugins/scroll/index.js +61 -0
  125. package/test/01-general.test.js +92 -23
  126. package/test/02-key.test.js +241 -40
  127. package/test/03-click.test.js +291 -47
  128. package/test/04-form.test.js +241 -47
  129. package/test/05-hover.test.js +463 -0
  130. package/test/06-scroll.test.js +374 -0
  131. package/test-helpers/Block.jsx +3 -2
  132. package/test-helpers/style.css +6 -1
  133. package/tsconfig.json +2 -1
  134. package/vitest.config.js +13 -11
  135. package/How..to.make.plugins.md +0 -41
@@ -1,6 +1,54 @@
1
1
  # Migration Guides
2
2
 
3
3
 
4
+ ## From version 3.x.x to version 4.0.0 (Upcoming)
5
+
6
+ ### Plugin Target Attributes Changes
7
+
8
+ **Breaking Changes:**
9
+ - Plugin `click` parameter `clickTarget` now accepts an **array of attribute names** instead of a single string
10
+ - Plugin `hover` parameter `hoverTarget` now accepts an **array of attribute names** instead of a single string
11
+
12
+ **Migration Required:**
13
+
14
+ ```js
15
+ // Version 3.x.x (old)
16
+ short.enablePlugin(pluginClick, { clickTarget: 'data-button' })
17
+ short.enablePlugin(pluginHover, { hoverTarget: 'data-menu' })
18
+
19
+ // Version 4.0.0 (new)
20
+ short.enablePlugin(pluginClick, { clickTarget: ['data-button'] })
21
+ short.enablePlugin(pluginHover, { hoverTarget: ['data-menu'] })
22
+ ```
23
+
24
+ **Default Values Updated:**
25
+ - `clickTarget` default: `['data-click', 'href']` (was `'data-click'`)
26
+ - `hoverTarget` default: `['data-hover']` (was `'data-hover'`)
27
+
28
+ **Benefits:**
29
+ - More flexible target detection
30
+ - Support for multiple attribute patterns
31
+ - Better compatibility with existing HTML patterns
32
+
33
+ ### Per-Context Setup Examples Updated
34
+
35
+ All setup examples in the documentation have been updated to use arrays:
36
+
37
+ ```js
38
+ // Version 4.0.0 per-context setup
39
+ const shortcutDefinition = {
40
+ myContext: {
41
+ 'click:setup': () => ({
42
+ clickTarget: ['data-action', 'data-button', 'href'] // Array format
43
+ }),
44
+ 'hover:setup': () => ({
45
+ hoverTarget: ['data-interactive', 'data-hover'] // Array format
46
+ })
47
+ }
48
+ };
49
+ ```
50
+
51
+
4
52
  ## From version 2.x.x to version 3.x.x
5
53
 
6
54
  Reason for significant refactoring of the code was my desire to make the library extensible with a plugins. Plugins role is to convert DOM events to shortcut strings, then the core part will trigger the action functions related to the shortcut. Now we have a core, plugin interface and plugins. All listener for `keyboard` and `mouse clicks` are moved to plugins. Mouse events are tracked by `click` plugin and keyboard events are tracked by `key` plugin.
package/README.md CHANGED
@@ -1,3 +1,7 @@
1
+ <img src="shortcuts.png" width="100%" alt="Shortcuts" align="center" />
2
+
3
+
4
+
1
5
  # Shortcuts (@peter.naydenov/shortcuts)
2
6
 
3
7
  ![version](https://img.shields.io/github/package-json/v/peterNaydenov/shortcuts)
@@ -13,13 +17,42 @@ Currently existing plugins:
13
17
  - `key` - Converts keyboard events to shortcuts;
14
18
  - `click` - Converts mouse events to shortcuts;
15
19
  - `form` - Form element changes to shortcuts;
16
-
17
- Planned work on plugins: `scroll`, `drag-drop`, etc.
20
+ - `hover` - Mouse hover events to shortcuts;
21
+ - `scroll` - Scroll events to shortcuts;
18
22
 
19
23
 
20
24
 
21
25
  ## Shortcut Description Rules
22
- The shortcuts definition includes a context name and a set of rules(object). The rules are a set of key-value pairs. The key is a shortcut name and the value is a function or array of functions, to be executed when the shortcut is triggered (action function).
26
+ 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).
27
+
28
+ ### Per-Context Plugin Setup (Preferred Method)
29
+ Every plugin supports a `setup` event (e.g., `key:setup`, `click:setup`, `hover:setup`, `scroll:setup`) that allows you to configure plugin settings specifically for that context. This is the **preferred method** for customizing plugins as it provides:
30
+
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
+
35
+ The setup function receives:
36
+ - `dependencies` - External dependencies set via `setDependencies()`
37
+ - `defaults` - Default plugin options as a starting point
38
+
39
+ Example pattern:
40
+ ```js
41
+ const shortcutDefinition = {
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
+ };
53
+ ```
54
+
55
+ See individual plugin sections for specific setup examples.
23
56
 
24
57
  ```js
25
58
  // { context: { shortcutName: actionFunction } }
@@ -50,9 +83,9 @@ Load a shortcut definition by calling `load` method.
50
83
 
51
84
  ```js
52
85
  // for es6 module projects:
53
- import { shortcuts, pluginKey, pluginClick, pluginForm } from '@peter.naydenov/shortcuts'
86
+ import { shortcuts, pluginKey, pluginClick, pluginForm, pluginHover, pluginScroll } from '@peter.naydenov/shortcuts'
54
87
  // for commonjs projects:
55
- const { shortcuts, pluginKey, pluginClick, pluginForm } = require('@peter.naydenov/shortcuts')
88
+ const { shortcuts, pluginKey, pluginClick, pluginForm, pluginHover, pluginScroll } = require('@peter.naydenov/shortcuts')
56
89
 
57
90
 
58
91
 
@@ -76,7 +109,228 @@ To deactivate a context without starting other context, call `changeContext` met
76
109
 
77
110
  ```js
78
111
  short.changeContext ()
79
- ```
112
+ ```
113
+
114
+
115
+ ## Plugin 'hover' Shortcut Descriptions
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.
117
+
118
+ ```js
119
+ hover:on // Triggered when mouse enters a target element
120
+ hover:off // Triggered when mouse leaves a target element
121
+ ```
122
+
123
+ ### Define Hover Targets
124
+ Target HTML elements for `hover` plugin are defined by `data-hover` attribute. The value of the attribute is the name of the target. Example:
125
+
126
+ ```html
127
+ <div data-hover="menu">Menu content</div>
128
+ <!-- target name is 'menu' -->
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
+ ```
159
+
160
+ ### Per-Context Setup (Preferred Method)
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.
162
+
163
+ ```js
164
+ const shortcutDefinition = {
165
+ navigation: {
166
+ 'hover:setup': ({ dependencies, defaults }) => {
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
183
+ return {
184
+ wait: 800, // Slower hover detection
185
+ hoverTarget: ['data-tooltip', 'data-help'] // Different attributes for tooltips
186
+ };
187
+ },
188
+ 'hover:on': ({ target }) => {
189
+ // Show tooltip with delay
190
+ setTimeout(() => target.classList.add('visible'), 100);
191
+ }
192
+ }
193
+ };
194
+
195
+ short.enablePlugin(pluginHover);
196
+ short.load(shortcutDefinition);
197
+ short.changeContext('navigation'); // Uses navigation settings
198
+ // short.changeContext('slowTooltips'); // Uses tooltip settings
199
+ ```
200
+
201
+ The `hover:setup` function receives:
202
+ - `dependencies` - External dependencies set via `setDependencies()`
203
+ - `defaults` - Default plugin options as a starting point or just for reference
204
+
205
+ Example usage:
206
+
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
+
221
+ short.enablePlugin(pluginHover);
222
+ short.load(shortcutDefinition);
223
+ short.changeContext('navigation');
224
+ ```
225
+
226
+ ## Plugin 'scroll' Shortcut Descriptions
227
+ `Scroll` plugin is used to detect scroll events on the page. The plugin supports four main scroll directions:
228
+
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
+
237
+ ### Scroll Detection Settings
238
+ Scroll events are detected with specific timing and distance thresholds to avoid excessive triggering. The default settings are:
239
+
240
+ - `scrollWait`: 50ms - Delay between scroll events
241
+ - `endScrollWait`: 400ms - Delay when scroll was stopped
242
+ - `minSpace`: 40px - Minimum distance between scroll events
243
+
244
+ These can be customized by setting scroll plugin options:
245
+
246
+ ```js
247
+ short.enablePlugin ( pluginScroll, {
248
+ scrollWait: 100, // set delay to 100ms
249
+ endScrollWait: 600, // set end scroll delay to 600ms
250
+ minSpace: 60 // set minimum distance to 60px
251
+ })
252
+ ```
253
+
254
+ ### Per-Context Setup (Preferred Method)
255
+ Instead of global plugin options, you can use `scroll:setup` event to configure plugin settings per context. This is preferred method for customization.
256
+
257
+ ```js
258
+ const shortcutDefinition = {
259
+ sensitiveScrolling: {
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:
299
+
300
+ ```js
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
+ }
309
+ ```
310
+
311
+ Example usage:
312
+
313
+ ```js
314
+ const shortcutDefinition = {
315
+ scrollView: {
316
+ 'scroll:up': () => {
317
+ console.log('User scrolled up');
318
+ },
319
+ 'scroll:down': () => {
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');
331
+ ```
332
+
333
+ ```
80
334
 
81
335
  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.
82
336
 
@@ -151,6 +405,50 @@ Multiple clicks are detected automatically by time interval between clicks. The
151
405
  short.enablePlugin ( pluginClick, { mouseWait: 500 }) // set the interval to 500ms
152
406
  ```
153
407
 
408
+ ### Per-Context Setup (Preferred Method)
409
+ Instead of global plugin options, you can use `click:setup` event to configure plugin settings per context. This is preferred method for customization.
410
+
411
+ ```js
412
+ const shortcutDefinition = {
413
+ fastClicking: {
414
+ 'click:setup': ({ dependencies, defaults }) => {
415
+ // Fast clicking for gaming or rapid interactions
416
+ return {
417
+ mouseWait: 150, // Very fast click detection
418
+ clickTarget: ['data-game-btn', 'data-action'] // Array of attributes for game buttons
419
+ };
420
+ },
421
+ 'click:left-1': ({ target }) => {
422
+ console.log('Fast single click');
423
+ },
424
+ 'click:left-2': ({ target }) => {
425
+ console.log('Fast double click');
426
+ }
427
+ },
428
+ slowClicking: {
429
+ 'click:setup': ({ dependencies, defaults }) => {
430
+ // Slower clicking for form submissions or important actions
431
+ return {
432
+ mouseWait: 600, // Slower click detection
433
+ clickTarget: ['data-form-action', 'data-submit'] // Array of attributes for form actions
434
+ };
435
+ },
436
+ 'click:left-1': ({ target }) => {
437
+ console.log('Deliberate single click');
438
+ }
439
+ }
440
+ };
441
+
442
+ short.enablePlugin(pluginClick);
443
+ short.load(shortcutDefinition);
444
+ short.changeContext('fastClicking'); // Uses fast settings
445
+ // short.changeContext('slowClicking'); // Uses slow settings
446
+ ```
447
+
448
+ The `click:setup` function receives:
449
+ - `dependencies` - External dependencies set via `setDependencies()`
450
+ - `defaults` - Default plugin options as a starting point
451
+
154
452
  Read more in section `Options`.
155
453
 
156
454
 
@@ -162,7 +460,7 @@ Target HTML elements for `shortcuts` are defined by `data-click` attribute. The
162
460
  <!-- target name is 'id' -->
163
461
  ```
164
462
 
165
- Attribute is customizable by setting `clickTarget` click plugin option. Read more in section `Options`.
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`.
166
464
 
167
465
  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:
168
466
 
@@ -225,6 +523,45 @@ Order of describing keyboard event and modifier keys is not important, but seque
225
523
 
226
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`.
227
525
 
526
+ ### Per-Context Setup (Preferred Method)
527
+ Instead of global plugin options, you can use `key:setup` event to configure plugin settings per context. This is preferred method for customization.
528
+
529
+ ```js
530
+ const shortcutDefinition = {
531
+ fastTyping: {
532
+ 'key:setup': ({ dependencies, defaults }) => {
533
+ // Fast key detection for gaming or rapid input
534
+ return {
535
+ keyWait: 200, // Very fast sequence detection
536
+ streamKeys: (key) => console.log('Key pressed:', key) // Enable key streaming
537
+ };
538
+ },
539
+ 'key:a,b,c': () => console.log('Fast sequence triggered'),
540
+ 'key:ctrl+s': () => console.log('Fast save')
541
+ },
542
+ slowTyping: {
543
+ 'key:setup': ({ dependencies, defaults }) => {
544
+ // Slower key detection for accessibility or careful input
545
+ return {
546
+ keyWait: 800, // Slower sequence detection
547
+ streamKeys: false // Disable key streaming
548
+ };
549
+ },
550
+ 'key:a,b,c': () => console.log('Slow sequence triggered'),
551
+ 'key:ctrl+s': () => console.log('Careful save')
552
+ }
553
+ };
554
+
555
+ short.enablePlugin(pluginKey);
556
+ short.load(shortcutDefinition);
557
+ short.changeContext('fastTyping'); // Uses fast settings
558
+ // short.changeContext('slowTyping'); // Uses slow settings
559
+ ```
560
+
561
+ The `key:setup` function receives:
562
+ - `dependencies` - External dependencies set via `setDependencies()`
563
+ - `defaults` - Default plugin options as a starting point
564
+
228
565
  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 `Keyboard Action Functions`.
229
566
 
230
567
  Special characters that are available for your shortcut descriptions:
@@ -274,8 +611,8 @@ Definition Example:
274
611
  ```js
275
612
  const shortcutScope = {
276
613
  ...
277
- , 'form : watch' : () => 'input, button' // Will select all inputs and buttons elements on the page.
278
- , 'form : define' : ( target ) => { // Target is a DOM element selected by 'form: watch'
614
+ , 'form : watch' : ({dependencies}) => 'input, button' // Will select all inputs and buttons elements on the page.
615
+ , 'form : define' : ({ target, dependencies }) => { // Target is a DOM element selected by 'form: watch'
279
616
  if ( target.tagName === 'INPUT' ) { // Will define inputs as 'input' type
280
617
  return 'input' // (String) Custom according your preference
281
618
  }
@@ -283,14 +620,15 @@ const shortcutScope = {
283
620
  return 'button'
284
621
  }
285
622
  }
286
- , 'form : action' : () => [
623
+ , 'form : action' : ({ dependencies}) => [
287
624
  {
288
625
  fn: ({target}) => { console.log ( target)}
289
626
  , type : 'input' // According to 'form: define'
290
627
  , timing : 'in' // on focus in
291
628
  },
292
629
  {
293
- fn: ({target}) => { console.log ( 'extra')}
630
+ // Dependencies is available in action functions
631
+ fn: ({target, dependencies }) => { console.log ( 'extra')}
294
632
  , type : 'input'
295
633
  , timing : 'in' // on focus in
296
634
  },
@@ -314,11 +652,11 @@ Plugin `form` has a default versions for `form:watch` and `form:define` function
314
652
  ```js
315
653
  const _defaults = {
316
654
  watch : () => 'input, select, textarea, button, a'
317
- , define: (el) => {
318
- if ( el.type === 'checkbox' || el.type === 'radio' ) {
655
+ , define: ({target}) => {
656
+ if ( target.type === 'checkbox' || target.type === 'radio' ) {
319
657
  return 'checkbox'
320
658
  }
321
- if ( el.type == 'button' || el.type=='submit' ) {
659
+ if ( target.type == 'button' || target.type=='submit' ) {
322
660
  return 'button'
323
661
  }
324
662
  return 'input'
@@ -328,6 +666,11 @@ const _defaults = {
328
666
 
329
667
  If you want to pause of resume event from `form` plugin, call `short.pause(eventName)` and `short.resume(eventName)` where eventName is a `${type}/${timing}`. Take type and timing from action definitions.
330
668
 
669
+ ### Per-Context Setup (Coming Soon)
670
+ 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
+
672
+ **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`.
673
+
331
674
 
332
675
 
333
676
  ## Action Functions
@@ -441,7 +784,20 @@ const short = shortcut ({onShortcut: (shortcut) => console.log(shortcut) }) // L
441
784
  ### Plugin 'click' options
442
785
  ```js
443
786
  mouseWait : 'Timeout for entering multiple mouse events. Default value - 320.'
444
- , clickTarget : 'Data attribute name to recognize click items in HTML. Default value - click' // data attribute 'click' means attribute ( data-click='someName' )
787
+ , clickTarget : 'Array of attribute names to recognize click items in HTML. Default value - ["data-click", "href"]' // checks for data-click='someName' or href attributes
788
+ ```
789
+
790
+ ### Plugin 'hover' options
791
+ ```js
792
+ wait : 'Time to wait for hover sequence in ms. Default value - 320.'
793
+ , hoverTarget : 'Array of attribute names to recognize hover items in HTML. Default value - ["data-hover"]' // checks for data-hover='someName' attribute
794
+ ```
795
+
796
+ ### Plugin 'scroll' options
797
+ ```js
798
+ scrollWait : 'Delay between scroll events in ms. Default value - 50.'
799
+ , endScrollWait : 'Delay when scroll was stopped in ms. Default value - 400.'
800
+ , minSpace : 'Minimum distance between scroll events in px. Default value - 40.'
445
801
  ```
446
802
 
447
803
  Plugin options are provided as a second argument during the plugin enabling. It's look like this:
@@ -454,7 +810,18 @@ Plugin options are provided as a second argument during the plugin enabling. It'
454
810
 
455
811
  short.enablePlugin ( pluginClick, {
456
812
  mouseWait: 200 // set the interval between multiple clicks to 200ms
457
- , clickTarget: 'puk' // data attribute 'puk' means attribute ( data-puk='someName' )
813
+ , clickTarget: ['data-puk', 'data-button'] // array of attribute names to check
814
+ })
815
+
816
+ short.enablePlugin ( pluginHover, {
817
+ wait: 500 // set the hover delay to 500ms
818
+ , hoverTarget: ['data-hover-me', 'data-interactive'] // array of attribute names to check
819
+ })
820
+
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
458
825
  })
459
826
 
460
827
  ```
@@ -490,18 +857,22 @@ Plugin options are provided as a second argument during the plugin enabling. It'
490
857
  The library includes TypeScript definitions. Install the package and TypeScript will automatically detect the types.
491
858
 
492
859
  ```typescript
493
- import { shortcuts, pluginKey, pluginClick, pluginForm } from '@peter.naydenov/shortcuts';
860
+ import { shortcuts, pluginKey, pluginClick, pluginForm, pluginHover, pluginScroll } from '@peter.naydenov/shortcuts';
494
861
 
495
862
  const short: ShortcutsAPI = shortcuts();
496
- short.enablePlugin(pluginKey);
497
- short.enablePlugin(pluginClick);
498
- short.enablePlugin(pluginForm);
863
+ const shortcutPlugins = [ pluginKey, pluginClick, pluginForm, pluginHover, pluginScroll ];
864
+ shortcutPlugins.forEach( plugin => short.enablePlugin(plugin) );
865
+
866
+
499
867
 
500
868
  // Type-safe shortcut definitions
501
869
  const shortcutDefinition = {
502
870
  myContext: {
503
871
  'key:ctrl+s': () => console.log('Saved'),
504
- 'click:left-1': (args: { target: HTMLElement }) => console.log('Clicked', args.target)
872
+ 'click:left-1': (args: { target: HTMLElement }) => console.log('Clicked', args.target),
873
+ 'hover:on': (args: { target: HTMLElement }) => console.log('Hovered', args.target),
874
+ 'scroll:down': () => console.log('Scrolled down'),
875
+ 'scroll:end': () => console.log('Scrolling ended')
505
876
  }
506
877
  };
507
878
 
@@ -513,10 +884,11 @@ The `ShortcutsAPI` interface provides full type safety for all methods and their
513
884
 
514
885
  ## Links
515
886
 
516
- - [History of changes](https://github.com/PeterNaydenov/shortcuts/blob/main/Changelog.md)
517
- - [Migration guide](https://github.com/PeterNaydenov/shortcuts/blob/main/Migration.guide.md)
887
+ - [API reference](https://github.com/PeterNaydenov/shortcuts/blob/main/API.md)
518
888
  - [How to make a plugin](https://github.com/PeterNaydenov/shortcuts/blob/main/How.to.make.plugins.md)
519
-
889
+ - [ Build a SPA apps with shortcuts (@peter.naydenov/cuts)](https://github.com/PeterNaydenov/cuts )
890
+ - [History of changes - changelog](https://github.com/PeterNaydenov/shortcuts/blob/main/Changelog.md)
891
+ - [Migration guide](https://github.com/PeterNaydenov/shortcuts/blob/main/Migration.guide.md)
520
892
 
521
893
 
522
894
  ## Credits
package/dist/main.d.ts CHANGED
@@ -1,3 +1,43 @@
1
+ export type dependencies = {
2
+ /**
3
+ * - Event emitter instance
4
+ */
5
+ ev: any;
6
+ /**
7
+ * - Internal API object
8
+ */
9
+ inAPI: any;
10
+ /**
11
+ * - Public API object
12
+ */
13
+ API: any;
14
+ /**
15
+ * - Extra dependencies object
16
+ */
17
+ extra: any;
18
+ };
19
+ export type state = {
20
+ /**
21
+ * - Current context data container with name and note properties
22
+ */
23
+ currentContext: any;
24
+ /**
25
+ * - Shortcuts object: { contextName : { shortcut : callback[] } }
26
+ */
27
+ shortcuts: any;
28
+ /**
29
+ * - Array of active plugins
30
+ */
31
+ plugins: any[];
32
+ /**
33
+ * - Keyboard shortcut log function
34
+ */
35
+ exposeShortcut: Function | null;
36
+ /**
37
+ * - Name for error events
38
+ */
39
+ ERROR_EVENT_NAME: string;
40
+ };
1
41
  export type PluginAPI = {
2
42
  /**
3
43
  * - Get plugin prefix
@@ -24,6 +64,16 @@ export type PluginAPI = {
24
64
  */
25
65
  destroy: () => void;
26
66
  };
67
+ export type contextShortcuts = {
68
+ /**
69
+ * - Context name
70
+ */
71
+ context: string;
72
+ /**
73
+ * - List of shortcuts in a context
74
+ */
75
+ shortcuts: string[];
76
+ };
27
77
  export type ShortcutsAPI = {
28
78
  /**
29
79
  * - Enable a plugin
@@ -92,7 +142,7 @@ export type ShortcutsAPI = {
92
142
  /**
93
143
  * - List shortcuts
94
144
  */
95
- listShortcuts: (arg0: string | null) => string[] | any[];
145
+ listShortcuts: (arg0: string | null) => string[] | contextShortcuts[] | null;
96
146
  /**
97
147
  * - Load shortcuts into contexts
98
148
  */
@@ -117,4 +167,6 @@ declare function main(options?: {
117
167
  import pluginKey from './plugins/key/index.js';
118
168
  import pluginClick from './plugins/click/index.js';
119
169
  import pluginForm from './plugins/form/index.js';
120
- export { main as shortcuts, pluginKey, pluginClick, pluginForm };
170
+ import pluginHover from './plugins/hover/index.js';
171
+ import pluginScroll from './plugins/scroll/index.js';
172
+ export { main as shortcuts, pluginKey, pluginClick, pluginForm, pluginHover, pluginScroll };