@peter.naydenov/shortcuts 4.0.1 → 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.
Files changed (89) hide show
  1. package/AGENTS.md +54 -0
  2. package/Changelog.md +14 -0
  3. package/README.md +935 -426
  4. package/dist/plugins/click/_listenDOM.d.ts +2 -2
  5. package/dist/plugins/form/_listenDOM.d.ts +4 -4
  6. package/dist/plugins/hover/_listenDOM.d.ts +2 -2
  7. package/dist/plugins/key/_listenDOM.d.ts +2 -2
  8. package/dist/plugins/scroll/_listenDOM.d.ts +2 -2
  9. package/dist/shortcuts.cjs +1 -1
  10. package/dist/shortcuts.esm.mjs +1 -1
  11. package/dist/shortcuts.umd.js +1 -1
  12. package/graphify-out/.graphify_benchmark.json +35 -0
  13. package/graphify-out/.graphify_python +1 -0
  14. package/graphify-out/GRAPH_REPORT.md +121 -0
  15. package/graphify-out/cache/024633ee076562ce0dbc0bf3b5315906f4e5d48c57bc96856b98cd5d42a69009.json +1 -0
  16. package/graphify-out/cache/037d2ba5552034c06beca677b1914ac7a053f696dfeaf12ca0de06eb42659f18.json +1 -0
  17. package/graphify-out/cache/055bfc2a3bfb8747f7ee0b7335704d2dff1c071d25a9bdd4f954e4cc2d630772.json +1 -0
  18. package/graphify-out/cache/0b2f626892ed04f158e39593dbf5f266c2a5982a21b2dddb144edc79af81e2d1.json +1 -0
  19. package/graphify-out/cache/0c17fe866170c4ab4023ac0680d1e05c5dc232a17ac0f08dfa1e76c2eaf75c44.json +1 -0
  20. package/graphify-out/cache/1392dca26291b5396829f1a996aac2c1d34a03d134a5fcf54e4f15824ee74e2b.json +1 -0
  21. package/graphify-out/cache/18113cd08ebffb11ed91ffab9c6d34795e22bfb5993941db07a52eed6eba45b8.json +1 -0
  22. package/graphify-out/cache/1a7a71b157cadd117435818e1a6561157c2930c4066d3a207fe04e318f76b296.json +1 -0
  23. package/graphify-out/cache/2448db4b822a94d6f3512ce8788077f35dfb567aef8628a846fad841b40575e7.json +1 -0
  24. package/graphify-out/cache/2592868b7b9d2de3f2cb575b7bd68ca2f252d34f71c12f2e8721d789cfbfbf88.json +1 -0
  25. package/graphify-out/cache/2aaf58292523f67421e6f728fd97740c5bf07dd903cf267cf557a4383759ba5e.json +1 -0
  26. package/graphify-out/cache/349a418954e66e5ef45370dca740ebff559a72d11f5810f6d40c0af14ef768e0.json +1 -0
  27. package/graphify-out/cache/361eacb4abb14862b75257bdf673a353826bf5764fb187ccde94ae21454bcf99.json +1 -0
  28. package/graphify-out/cache/40b4c82a11a2a31b279563c143d91d7894eb3f3d0c386f8323cb8062bcdfadd5.json +1 -0
  29. package/graphify-out/cache/40db98ff036ad694953cb13628795fabc0c5892ff093dfdcc18a309ac0d10846.json +1 -0
  30. package/graphify-out/cache/43a590ac22f05be183ea1a4655922185595c969f79dd3df3d44d1c7e49355785.json +1 -0
  31. package/graphify-out/cache/4993a6e98dcf33bb6fa78341b4eeac4776e2322f10522eecdc5195aa7969f35a.json +1 -0
  32. package/graphify-out/cache/5095c6e52a24f4ecec9acf63835761ad508df88d56b1799faec47672fbd4e348.json +1 -0
  33. package/graphify-out/cache/5cba1d38ffea01d8c62e5a0b0d8b164cf9b115ff1b6f1acc606f78877712d5de.json +1 -0
  34. package/graphify-out/cache/67aadf0b8f90224cb725e903e6fedbf6828f203467a633f98031b0740930cb21.json +1 -0
  35. package/graphify-out/cache/68dffbffbd811942d85ef2600ca31e423d3c3c343de98cbba4c954c94dd11470.json +1 -0
  36. package/graphify-out/cache/69c684e506b9ce22e95aff044c1da4b0f88ef72c510da02a739edbe551372a8e.json +1 -0
  37. package/graphify-out/cache/6e336587fcfe2b298f23326e881f048d37f1bb062d00806c338da58a8fd281ca.json +1 -0
  38. package/graphify-out/cache/78d88737e6db913f091c4c48e96953df065f6808e2b60dd828fdee64067dac91.json +1 -0
  39. package/graphify-out/cache/7e5340b989299a0b7217d1fd0d2b919cba65142f3e468b0aca5f4ffd5c0594d8.json +1 -0
  40. package/graphify-out/cache/813d6bac52066ed8733781c35710ecb7995e6cabbe0d9abb9854e3c67610b974.json +1 -0
  41. package/graphify-out/cache/8180f34832546e874bc5f1931eee545d97300be49faac5c9b6d515653a763324.json +1 -0
  42. package/graphify-out/cache/885894ca90af6a3724182762bc4fc7ff7d22727a931d46fe7593d1eea10c0c71.json +1 -0
  43. package/graphify-out/cache/8a304ae8f6bf02bfa40923cdbea99e4bea943db52c185f22caa43ba7c34f94d3.json +1 -0
  44. package/graphify-out/cache/903a7dea28112a27dcc1b9ece66514f4d5dd6ca264f5ee70835aca069a8df2ad.json +1 -0
  45. package/graphify-out/cache/9831a7833c5bfeb9a0611e416f7038bd37884b42a9a720f9b4c0a01f860a4f54.json +1 -0
  46. package/graphify-out/cache/98dbdcdd1b19bc942850f50b1ebdeb1865c72ba724990217464efd28a3732b32.json +1 -0
  47. package/graphify-out/cache/a2459f621d588f0166ae6a4204bb6b89f9d669b3ad0c54a88afac6c7abb134b4.json +1 -0
  48. package/graphify-out/cache/a25d47ecf087fa6888d641f89f08cefd35c68b5823c8c55b3baa0243ab110110.json +1 -0
  49. package/graphify-out/cache/a3bd22d8493943a3195c3ef1254a7240624a962edf2baa2c30eb0ae60564fbe7.json +1 -0
  50. package/graphify-out/cache/a4d4fb674183a3b348f542b1b9fb9c0d7b176c43636afb2554af088a9613a1c0.json +1 -0
  51. package/graphify-out/cache/a87a705106773b14c5a25697d30c743cdab01df551cdd9892d6ec46f98ad1659.json +1 -0
  52. package/graphify-out/cache/a9416d0397b5fb994b8c3847aea2599a9d33940e6f0652accc5ba1de478349ee.json +1 -0
  53. package/graphify-out/cache/ab03b9df0e9b8a74db3782c96fee833d800d93838fc0c056306ac2ef9a3e0c09.json +1 -0
  54. package/graphify-out/cache/ad3a99182567225cc19374c28d33097f146547bd945967c723b66d1065134ce9.json +1 -0
  55. package/graphify-out/cache/aece91cfc3a5181bbb77a1758921dfb6a323ab04cc402ce42f2832446d04f420.json +1 -0
  56. package/graphify-out/cache/bd65fd515423e8964058f6aa997c05e3e0fb9e6d39209d4a1d76a079c6af46e8.json +1 -0
  57. package/graphify-out/cache/c2a85071784f9516ab2dea976eeb3a514a53b15701bbf60b4d8be6cd3385cd6c.json +1 -0
  58. package/graphify-out/cache/c9a8c9342926031f308af0eb0a8d60cf0b443e84bae839da42998956465e47e6.json +1 -0
  59. package/graphify-out/cache/d05c0aa647a624e0c696f53c027d066c35d0893695e9a23fd820235ee86b4a70.json +1 -0
  60. package/graphify-out/cache/d3d9832015ab51f52ae88375cea2cbeabecd4a000578e28e899ce23e74245733.json +1 -0
  61. package/graphify-out/cache/d449ad503a40840d41cbf24ed57f408bf5fdf891f830990f836cf52da5c605eb.json +1 -0
  62. package/graphify-out/cache/d92b22194973f3c39ac53d85a29f5d4837d07b0f9f0d375e3ddce8da158777fb.json +1 -0
  63. package/graphify-out/cache/dda8f89f688d8a4db8b7279031ad26a0d8d4accc0aa049abda5fa19eac4bd5ef.json +1 -0
  64. package/graphify-out/cache/e1d80dbca10b7e2ba65339eff0649699c6091d30b836a1e9d5d094bb95aacc48.json +1 -0
  65. package/graphify-out/cache/e207108277cbe1af0501688b0268fea879d0414424386fbaa93a5861f306bdba.json +1 -0
  66. package/graphify-out/cache/e6032dad287da859a517d6b59105595db90e81833dbd850b37653bbd0f3acef7.json +1 -0
  67. package/graphify-out/cache/f49d7295a833de68579e0e265832bc78d21e901764e31705423e621a703124dc.json +1 -0
  68. package/graphify-out/cache/fcf90a1251a332948a773c6aaaad4ce7f6de8d2f2333687cb2fe94e0d860a6c9.json +1 -0
  69. package/graphify-out/cache/fe06fcb623d36858b89c8741696482530a084f599d48bea88de7943fae0f9bea.json +1 -0
  70. package/graphify-out/cache/ffa0f819e023809d17aac1af75cf0f6fbf08500615aee27341b658f24357105a.json +1 -0
  71. package/graphify-out/cost.json +12 -0
  72. package/graphify-out/graph.html +266 -0
  73. package/graphify-out/graph.json +634 -0
  74. package/graphify-out/manifest.json +124 -0
  75. package/how-to-create-a-plugin.md +573 -0
  76. package/package.json +23 -21
  77. package/src/main.js +5 -5
  78. package/src/plugins/click/_listenDOM.js +3 -3
  79. package/src/plugins/form/_listenDOM.js +7 -6
  80. package/src/plugins/hover/_listenDOM.js +2 -2
  81. package/src/plugins/key/_listenDOM.js +4 -4
  82. package/src/plugins/scroll/_listenDOM.js +1 -1
  83. package/test/01-general.test.js +1 -1
  84. package/test/02-key.test.js +45 -1
  85. package/test/03-click.test.js +51 -2
  86. package/test/04-form.test.js +26 -1
  87. package/test/05-hover.test.js +50 -2
  88. package/test/06-scroll.test.js +21 -0
  89. package/How.to.create.plugins.md +0 -929
package/src/main.js CHANGED
@@ -100,7 +100,7 @@ function main ( options = {} ) {
100
100
  const
101
101
  inAPI = {} // API for internal methods
102
102
  , API = {} // API for public methods
103
- , ev = notice () // Event emitter instance
103
+ , ev = notice () // Event emitter instance
104
104
  , state = {
105
105
  currentContext : { name: null, note: null } // Context data container
106
106
  , shortcuts : {} // shortcuts = { contextName : { shortcut : callback[] } }
@@ -113,7 +113,7 @@ function main ( options = {} ) {
113
113
  ev
114
114
  , inAPI
115
115
  , API
116
- , extra : {}
116
+ , extra : { emit: ev.emit }
117
117
  };
118
118
 
119
119
  // ---------------------- > PLUGIN METHODS < ---------------------- //
@@ -232,10 +232,10 @@ function main ( options = {} ) {
232
232
  * @function emit
233
233
  * @description Emit event for shortcut in current context
234
234
  * @param {string} name - Shortcut name
235
- * @param {any} [args] - Arguments for callback function
235
+ * @param {...any} [args] - Arguments forwarded to the shortcut callback as additional positional parameters
236
236
  * @returns {void}
237
237
  **/
238
- API.emit = (name,...args) => ev.emit ( inAPI._readShortcutWithPlugins ( name ), ...args )
238
+ API.emit = (name,...args) => ev.emit ( inAPI._readShortcutWithPlugins ( name ), { dependencies: dependencies.extra, type: 'custom' }, ...args )
239
239
 
240
240
 
241
241
  /**
@@ -273,7 +273,7 @@ function main ( options = {} ) {
273
273
  API.changeContext ()
274
274
  state.plugins.forEach ( plugin => plugin.destroy () )
275
275
  API.listContexts ().map ( cx => API.unload ( cx ))
276
- dependencies.extra = {}
276
+ dependencies.extra = { emit: ev.emit }
277
277
  state.exposeShortcut = null
278
278
  } // reset func.
279
279
 
@@ -16,7 +16,7 @@
16
16
  * @property {string|null} note - Current context note
17
17
  * @property {Object} options - Plugin state listenOptions (reference to pluginState.listenOptions)
18
18
  * @property {Event} event - The original DOM event
19
- * @property {Object} dependencies - Extra dependencies object
19
+ * @property {Object} dependencies - Reference to the library's `extra` bag. Always includes `emit: ev.emit` plus any keys you set via `short.setDependencies({...})`
20
20
  * @property {Object} viewport - Viewport information with X, Y, width, height
21
21
  * @property {Object} sizes - Element dimensions with width, height
22
22
  * @property {Object} position - Element position relative to viewport with x, y
@@ -24,9 +24,9 @@
24
24
  * @property {string} type - Event type ('click')
25
25
  */
26
26
  function _listenDOM ( dependencies, state ) {
27
- const {
27
+ const {
28
28
  ev
29
- , _findTarget
29
+ , _findTarget
30
30
  , _readClickEvent
31
31
  , extra
32
32
  } = dependencies
@@ -14,19 +14,20 @@
14
14
  * @property {string} context - Current context name
15
15
  * @property {string|null} note - Current context note
16
16
  * @property {Event} event - The original DOM event
17
- * @property {Object} dependencies - Extra dependencies object
17
+ * @property {Object} dependencies - Reference to the library's `extra` bag. Always includes `emit: ev.emit` plus any keys you set via `short.setDependencies({...})`
18
18
  * @property {Object} options - Plugin state listenOptions (reference to pluginState.listenOptions)
19
19
  * @property {Object} viewport - Viewport information with X, Y, width, height
20
20
  * @property {Object} sizes - Element dimensions with width, height
21
21
  * @property {Object} position - Element position relative to viewport with x, y
22
22
  * @property {Object} pagePosition - Element position relative to page with x, y
23
- * @property {string} type - Event type ('form-in', 'form-out', 'form-instant')
23
+ * @property {string} type - Event type ('form'). The timing (in/out/instant) lives in the emitted event name (e.g. `email/in`, `email/instant`)
24
24
  */
25
25
  function _listenDOM ( dependencies, state ) {
26
26
  const { ev } = dependencies;
27
27
  let timeout = null;
28
28
 
29
29
  function setupData ( dependencies, state, event, type) {
30
+ const { extra } = dependencies;
30
31
  const
31
32
  { left, top, width, height } = event.target.getBoundingClientRect ()
32
33
  , scrollX = window.scrollX
@@ -37,7 +38,7 @@ function _listenDOM ( dependencies, state ) {
37
38
  , context : state.currentContext.name
38
39
  , note : state.currentContext.note
39
40
  , event
40
- , dependencies : dependencies.extra
41
+ , dependencies : extra
41
42
  , options : state.listenOptions
42
43
  , viewport : { // Viewport scroll positions and sizes
43
44
  X:scrollX
@@ -56,7 +57,7 @@ function _listenDOM ( dependencies, state ) {
56
57
  const
57
58
  { callbacks, typeFn } = state
58
59
  , target = event.target
59
- , prop = setupData ( dependencies, state, event, "form-in" )
60
+ , prop = setupData ( dependencies, state, event, "form" )
60
61
  , type = typeFn ( prop )
61
62
  , key = `${type}/in`
62
63
  ;
@@ -67,7 +68,7 @@ function _listenDOM ( dependencies, state ) {
67
68
  function listenFocusOut ( event ) { // Timing: out
68
69
  const
69
70
  { callbacks, typeFn } = state
70
- , prop = setupData ( dependencies, state, event, "form-out" )
71
+ , prop = setupData ( dependencies, state, event, "form" )
71
72
  , type = typeFn ( prop )
72
73
  , key = `${type}/out`
73
74
  ;
@@ -79,7 +80,7 @@ function _listenDOM ( dependencies, state ) {
79
80
  function listenInput ( event ) { // Timing: instant
80
81
  const
81
82
  { callbacks, typeFn } = state
82
- , prop = setupData ( dependencies, state, event, "form-instant" )
83
+ , prop = setupData ( dependencies, state, event, "form" )
83
84
  , type = typeFn ( prop )
84
85
  , wait = state.wait[`${type}`]
85
86
  , key = `${type}/instant`
@@ -11,7 +11,7 @@
11
11
  * @property {string} context - Current context name
12
12
  * @property {string|null} note - Current context note
13
13
  * @property {Event} event - The original DOM event
14
- * @property {Object} dependencies - Extra dependencies object
14
+ * @property {Object} dependencies - Reference to the library's `extra` bag. Always includes `emit: ev.emit` plus any keys you set via `short.setDependencies({...})`
15
15
  * @property {Object} options - Plugin state listenOptions (reference to pluginState.listenOptions)
16
16
  * @property {Object} viewport - Viewport information with X, Y, width, height
17
17
  * @property {Object} sizes - Element dimensions with width, height
@@ -68,7 +68,7 @@ function listenForHover ( event ) {
68
68
  ;
69
69
 
70
70
  return {
71
- target : tg
71
+ target : tg
72
72
  , context: state.currentContext.name
73
73
  , note : state.currentContext.note
74
74
  , event
@@ -16,14 +16,14 @@
16
16
  * @property {Function} isWaiting - Function to check if currently waiting for keys
17
17
  * @property {string|null} note - Current context note
18
18
  * @property {string} context - Current context name
19
- * @property {Object} dependencies - Extra dependencies object
19
+ * @property {Object} dependencies - Reference to the library's `extra` bag. Always includes `emit: ev.emit` plus any keys you set via `short.setDependencies({...})`
20
20
  * @property {Object} options - Plugin state listenOptions (reference to pluginState.listenOptions)
21
21
  * @property {Object} viewport - Viewport information with X, Y, width, height
22
22
  * @property {string} type - Event type ('key')
23
23
  */
24
24
  function _listenDOM ( dependencies, state ) {
25
25
  // Listen for input signals and generate event titles
26
- const {
26
+ const {
27
27
  ev
28
28
  , _specialChars
29
29
  , _readKeyEvent
@@ -67,11 +67,11 @@ function _listenDOM ( dependencies, state ) {
67
67
  , context: currentContext.name
68
68
  , dependencies : extra
69
69
  , options : state.listenOptions
70
- , viewport : {
70
+ , viewport : {
71
71
  X : window.scrollX
72
72
  , Y : window.scrollY
73
73
  , width:window.innerWidth
74
- , height:window.innerHeight
74
+ , height:window.innerHeight
75
75
  }
76
76
  , type : 'key'
77
77
  };
@@ -13,7 +13,7 @@
13
13
  * @property {string} direction - Scroll direction ('up', 'down', 'left', 'right')
14
14
  * @property {string} context - Current context name
15
15
  * @property {string|null} note - Current context note
16
- * @property {Object} dependencies - Extra dependencies object
16
+ * @property {Object} dependencies - Reference to the library's `extra` bag. Always includes `emit: ev.emit` plus any keys you set via `short.setDependencies({...})`
17
17
  * @property {Object} options - Plugin state listenOptions (reference to pluginState.listenOptions)
18
18
  * @property {Object} viewport - Viewport information with X, Y, width, height
19
19
  * @property {string} type - Event type ('scroll')
@@ -218,7 +218,7 @@ describe ( "Shortcuts", () => {
218
218
  const myAllContext = {
219
219
  myAll: {
220
220
  'click : leff-1' : () => 'nothing'
221
- , 'yo' : ({msg}) => result = msg
221
+ , 'yo' : (x,{msg}) => result = msg
222
222
  }}
223
223
  short.load ( myAllContext )
224
224
  short.changeContext ( 'myAll' )
@@ -464,10 +464,54 @@ describe ( 'Key plugin', () => {
464
464
  expect ( emit[0] ).to.equal ( 'setup' )
465
465
 
466
466
  // Click and measure time
467
- await userEvent.keyboard ( 'a')
467
+ await userEvent.keyboard ( 'a' )
468
468
  await waitFor ( () => {
469
469
  expect ( emit ).to.deep.equal ( [ 'setup', 'a' ] )
470
470
  }, { timeout: 1000, interval: 12 })
471
471
  }) // it extra parameters to plugin options
472
472
 
473
+
474
+
475
+ it ( 'Key callback data contains emit property', async () => {
476
+ let captured = null
477
+ short.enablePlugin ( pluginKey )
478
+ short.load ({
479
+ 'local' : {
480
+ 'key: a' : ( data ) => captured = data
481
+ }
482
+ })
483
+ short.changeContext ( 'local' )
484
+ await userEvent.keyboard ( 'a' )
485
+ await wait ( 20 )
486
+ await waitFor ( () => {
487
+ const { emit } = captured.dependencies;
488
+ expect ( captured ).toBeTruthy ()
489
+ expect ( typeof emit ).toBe ( 'function' )
490
+ }, { timeout: 1000, interval: 12 })
491
+ }) // it key callback data contains emit property
492
+
493
+
494
+
495
+ it ( 'Key callback can emit other events via data.dependencies.emit (workflow)', async () => {
496
+ const log = []
497
+ short.enablePlugin ( pluginKey )
498
+ short.load ({
499
+ 'local' : {
500
+ 'key: a' : ( k ) => {
501
+ log.push ( 'a-fired' )
502
+ k.dependencies.emit ( '@hidden' )
503
+ }
504
+ , '@hidden' : () => {
505
+ log.push ( 'hidden-fired' )
506
+ }
507
+ }
508
+ })
509
+ short.changeContext ( 'local' )
510
+ await userEvent.keyboard ( 'a' )
511
+ await wait ( 50 )
512
+ await waitFor ( () => {
513
+ expect ( log ).to.deep.equal ( [ 'a-fired', 'hidden-fired' ] )
514
+ }, { timeout: 1000, interval: 12 })
515
+ }) // it key callback workflow
516
+
473
517
  })
@@ -587,10 +587,59 @@ describe ( 'Click plugin', () => {
587
587
  const target = document.querySelector ( '[data-hover="blue"]' );
588
588
 
589
589
  // Click and measure time
590
- await userEvent.click ( target )
590
+ await userEvent.click ( target )
591
591
  await waitFor ( () => {
592
592
  expect ( emit ).to.deep.equal ( [ 'setup', 'clicked' ] )
593
593
  }, { timeout: 1000, interval: 12 })
594
594
  }) // it extra parameters to plugin options
595
-
595
+
596
+
597
+
598
+ it ( 'Click callback data contains emit property', async () => {
599
+ let captured = null
600
+ short.enablePlugin ( pluginClick )
601
+ short.load ({
602
+ 'local' : {
603
+ 'click: left-1' : ( data ) => {
604
+ captured = data
605
+ }
606
+ }
607
+ })
608
+ short.changeContext ( 'local' )
609
+ const megaBtn = document.querySelector ( '[data-click="mega"]' )
610
+ expect ( megaBtn ).to.not.be.null
611
+ await userEvent.click ( megaBtn )
612
+ await wait ( 50 )
613
+ await waitFor ( () => {
614
+ expect ( captured ).toBeTruthy ()
615
+ expect ( typeof captured.dependencies.emit ).toBe ( 'function' )
616
+ }, { timeout: 1000, interval: 12 })
617
+ }) // it click callback data contains emit property
618
+
619
+
620
+
621
+ it ( 'Click callback can emit other events via data.dependencies.emit (workflow)', async () => {
622
+ const log = []
623
+ short.enablePlugin ( pluginClick )
624
+ short.load ({
625
+ 'local' : {
626
+ 'click: left-1' : ( data ) => {
627
+ log.push ( 'left-1-fired' )
628
+ data.dependencies.emit ( 'CLICK:RIGHT-1' )
629
+ }
630
+ , 'click: right-1' : () => {
631
+ log.push ( 'right-1-fired' )
632
+ }
633
+ }
634
+ })
635
+ short.changeContext ( 'local' )
636
+ const megaBtn = document.querySelector ( '[data-click="mega"]' )
637
+ expect ( megaBtn ).to.not.be.null
638
+ await userEvent.click ( megaBtn )
639
+ await wait ( 50 )
640
+ await waitFor ( () => {
641
+ expect ( log ).to.deep.equal ( [ 'left-1-fired', 'right-1-fired' ] )
642
+ }, { timeout: 1000, interval: 12 })
643
+ }) // it click callback workflow
644
+
596
645
  }) // describe
@@ -323,5 +323,30 @@ describe ( 'Form plugin', () => {
323
323
  expect ( emit ).to.includes ( 'executed' )
324
324
  }, { timeout: 1000, interval: 12 })
325
325
  }) // it Extra parameters to plugin options
326
-
326
+
327
+
328
+
329
+ it ( 'Form action fn receives emit property on data', async () => {
330
+ let captured = null
331
+ short.enablePlugin ( pluginForm )
332
+ short.load ({
333
+ 'local' : {
334
+ 'form: action' : () => [{
335
+ fn : ( data ) => { captured = data }
336
+ , type : 'input'
337
+ , timing : 'in'
338
+ }]
339
+ }
340
+ })
341
+ short.changeContext ( 'local' )
342
+ const input = document.getElementById ( 'name' )
343
+ expect ( input ).to.not.be.null
344
+ input.focus ()
345
+ await wait ( 80 )
346
+ await waitFor ( () => {
347
+ expect ( captured ).toBeTruthy ()
348
+ expect ( typeof captured.dependencies.emit ).toBe ( 'function' )
349
+ }, { timeout: 1000, interval: 12 })
350
+ }) // it form action fn data contains emit property
351
+
327
352
  }) // describe
@@ -458,6 +458,54 @@ describe ( 'Hover plugin', () => {
458
458
  }, { timeout: 1000, interval: 12 })
459
459
  }) // it extra parameters to plugin options
460
460
 
461
-
462
-
461
+
462
+
463
+ it ( 'Hover callback data contains emit property', async () => {
464
+ let captured = null
465
+ short.enablePlugin ( pluginHover )
466
+ short.load ({
467
+ 'local' : {
468
+ 'hover : on' : ( data ) => {
469
+ captured = data
470
+ }
471
+ }
472
+ })
473
+ short.changeContext ( 'local' )
474
+ const megaBtn = document.querySelector ( '[data-click="mega"]' )
475
+ expect ( megaBtn ).to.not.be.null
476
+ await userEvent.hover ( megaBtn )
477
+ await wait ( 340 )
478
+ await waitFor ( () => {
479
+ expect ( captured ).toBeTruthy ()
480
+ expect ( typeof captured.dependencies.emit ).toBe ( 'function' )
481
+ }, { timeout: 1000, interval: 12 })
482
+ }) // it hover callback data contains emit property
483
+
484
+
485
+
486
+ it ( 'Hover callback can emit other events via data.dependencies.emit (workflow)', async () => {
487
+ const log = []
488
+ short.enablePlugin ( pluginHover )
489
+ short.load ({
490
+ 'local' : {
491
+ 'hover : on' : ( data ) => {
492
+ log.push ( 'on-fired' )
493
+ data.dependencies.emit ( 'HOVER:OFF' )
494
+ }
495
+ , 'hover : off' : () => {
496
+ log.push ( 'off-fired' )
497
+ }
498
+ }
499
+ })
500
+ short.changeContext ( 'local' )
501
+ const megaBtn = document.querySelector ( '[data-click="mega"]' )
502
+ expect ( megaBtn ).to.not.be.null
503
+ await userEvent.hover ( megaBtn )
504
+ await wait ( 340 )
505
+ await waitFor ( () => {
506
+ expect ( log[0] ).toBe ( 'on-fired' )
507
+ expect ( log ).to.includes ( 'off-fired' )
508
+ }, { timeout: 1000, interval: 12 })
509
+ }) // it hover callback workflow
510
+
463
511
  }) // describe
@@ -371,4 +371,25 @@ it ( 'Disable a plugin', () => {
371
371
  expect ( scrollEvents.length ).to.be.greaterThan ( 0 )
372
372
  }) // it extra parameters to plugin options
373
373
 
374
+
375
+
376
+ it ( 'Scroll callback data contains emit property', async () => {
377
+ let captured = null
378
+ short.enablePlugin ( pluginScroll )
379
+ short.load ({
380
+ 'local' : {
381
+ 'scroll: down' : ( data ) => {
382
+ captured = data
383
+ }
384
+ }
385
+ })
386
+ short.changeContext ( 'local' )
387
+ window.scrollTo ( 0, 100 )
388
+ await wait ( 200 )
389
+ await waitFor ( () => {
390
+ expect ( captured ).toBeTruthy ()
391
+ expect ( typeof captured.dependencies.emit ).toBe ( 'function' )
392
+ }, { timeout: 1000, interval: 12 })
393
+ }) // it scroll callback data contains emit property
394
+
374
395
  }) // describe Scroll plugin