@peter.naydenov/shortcuts 3.3.1 → 3.4.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/Changelog.md CHANGED
@@ -1,55 +1,99 @@
1
1
  ## Release History
2
2
 
3
3
 
4
+
5
+ ### 3.4.0 ( 2025-10-18)
6
+ - [x] Feature: New method 'reset' to reset the library instance;
7
+ - [x] Refactoring: Added 'active' state property to 'click' plugin state management;
8
+ - [x] Test: Migrated Vitest configuration from deprecated workspace files to modern format;
9
+ - [x] Test: Added @vitest/ui package for interactive test interface;
10
+ - [x] Test: Updated click and key plugin tests for better reliability;
11
+ - [x] Dev deps update. @rollup/plugin-commonjs to v.28.0.8;
12
+ - [x] Dev deps update. Playwright to v.1.56.1;
13
+ - [x] Fix: Cleaning plugin-state variables on plugin stop;
14
+ - [x] Fix: Wrong plugin name detection in 'enablePlugin' method;
15
+ - [x] Fix: Custom events for plugins with works only with nomrmalized event-names. Fixed - event name normalization could be done from the enabled plugins;
16
+
17
+
18
+
4
19
  ### 3.3.1 ( 2025-10-10)
5
20
  - [x] Fix: Fail to react on 'key:specialCharacters' events
6
-
21
+ - [ ] Bug: Cleaning plugin-state variables on plugin stop;
22
+ - [ ] Bug: Wrong plugin name detection in 'enablePlugin' method;
23
+ - [ ] Bug: Custom events for plugins with works only with nomrmalized event-names;
7
24
 
8
25
 
9
26
 
10
27
  ### 3.3.0 ( 2025-09-29)
11
28
  - [x] Dependency updates and new build;
12
29
  - [ ] Bug: Fail to react on 'key:specialCharacters' events
30
+ - [ ] Bug: Cleaning plugin-state variables on plugin stop;
31
+ - [ ] Bug: Wrong plugin name detection in 'enablePlugin' method;
32
+ - [ ] Bug: Custom events for plugins with works only with nomrmalized event-names;
13
33
 
14
34
 
15
35
  ### 3.2.1 ( 2025-08-15)
16
36
  - [x] Fix: Old build files were not deleted after release.
17
37
  - [ ] Bug: Fail to react on 'key:specialCharacters' events
38
+ - [ ] Bug: Cleaning plugin-state variables on plugin stop;
39
+ - [ ] Bug: Wrong plugin name detection in 'enablePlugin' method;
40
+ - [ ] Bug: Custom events for plugins with works only with nomrmalized event-names;
18
41
 
19
42
 
20
43
  ### 3.2.0 ( 2025-08-15)
21
44
  - [x] Plugin 'form' was added. It allows you to listen for form elements changes.
22
45
  - [ ] Miss: Old build files were not deleted after release.
23
46
  - [ ] Bug: Fail to react on 'key:specialCharacters' events
47
+ - [ ] Bug: Cleaning plugin-state variables on plugin stop;
48
+ - [ ] Bug: Wrong plugin name detection in 'enablePlugin' method;
49
+ - [ ] Bug: Custom events for plugins with works only with nomrmalized event-names;
24
50
 
25
51
 
26
52
 
27
53
  ### 3.1.4 ( 2025-05-3)
28
54
  - [x] Dependency update. @peter.naydenov/notice - v.2.4.1
55
+ - [ ] Bug: Cleaning plugin-state variables on plugin stop;
56
+ - [ ] Bug: Wrong plugin name detection in 'enablePlugin' method;
57
+ - [ ] Bug: Custom events for plugins with works only with nomrmalized event-names;
29
58
 
30
59
 
31
60
  ### 3.1.3 ( 2025-01-12)
32
61
  - [x] Dependency update. @peter.naydenov/notice - v.2.4.0
62
+ - [ ] Bug: Cleaning plugin-state variables on plugin stop;
63
+ - [ ] Bug: Wrong plugin name detection in 'enablePlugin' method;
64
+ - [ ] Bug: Custom events for plugins with works only with nomrmalized event-names;
33
65
 
34
66
 
35
67
 
36
68
  ### 3.1.2 ( 2024-12-23 )
37
69
  - [x] Dependency update. @peter.naydenov/notice - v.2.3.2
70
+ - [ ] Bug: Cleaning plugin-state variables on plugin stop;
71
+ - [ ] Bug: Wrong plugin name detection in 'enablePlugin' method;
72
+ - [ ] Bug: Custom events for plugins with works only with nomrmalized event-names;
38
73
 
39
74
 
40
75
 
41
76
  ### 3.1.1 ( 2024-03-15 )
42
77
  - [x] Update: Using @peter.naydenov/notice v.2.3.1: Fix: Callback stop will stop the wildcard callbacks as well;
78
+ - [ ] Bug: Cleaning plugin-state variables on plugin stop;
79
+ - [ ] Bug: Wrong plugin name detection in 'enablePlugin' method;
80
+ - [ ] Bug: Custom events for plugins with works only with nomrmalized event-names;
43
81
 
44
82
 
45
83
 
46
84
  ### 3.1.0 ( 2024-03-14 )
47
85
  - [x] Using @peter.naydenov/notice v.2.3.0: If action function returns a string 'stop' and execution of followed action functions will be stopped. Option to build a chain of conditional action functions before the main action function;
86
+ - [ ] Bug: Cleaning plugin-state variables on plugin stop;
87
+ - [ ] Bug: Wrong plugin name detection in 'enablePlugin' method;
88
+ - [ ] Bug: Custom events for plugins with works only with nomrmalized event-names;
48
89
 
49
90
 
50
91
 
51
92
  ### 3.0.1 ( 2024-03-06 )
52
93
  - [x] Fix: Library works again;
94
+ - [ ] Bug: Cleaning plugin-state variables on plugin stop;
95
+ - [ ] Bug: Wrong plugin name detection in 'enablePlugin' method;
96
+ - [ ] Bug: Custom events for plugins with works only with nomrmalized event-names;
53
97
 
54
98
 
55
99
 
@@ -1 +1 @@
1
- "use strict";var t=require("@peter.naydenov/notice");var e={_normalizeWithPlugins:function(t,e){return function(t){const n=e.shortcuts;Object.keys(n).forEach(e=>{Object.entries(n[e]).forEach(([o,r])=>{const i=t(o);i!==o&&(delete n[e][o],n[e][i]=r)})})}},_readShortcutWithPlugins:function(t,e){return function(n){const{inAPI:o}=t,r=n.split(":")[0],i=o._systemAction(r,"none");let s=n;return-1!==i&&(s=e.plugins[i].shortcutName(n)),s}},_systemAction:function(t,e){return function(t,n,o=null){return e.plugins.findIndex(e=>e.getPrefix()===t&&(e[n]&&e[n](o),!0))}},changeContext:function(t,e){const{shortcuts:n,currentContext:o}=e,{ev:r}=t;return function(t=!1){const i=o.name;if(!t)return r.reset(),void(o.name=null);i!==t&&(n[t]?(n[i]&&r.reset(),o.name=t,e.plugins.forEach(e=>e.contextChange(t)),Object.entries(n[t]).forEach(([t,e])=>{e.forEach(e=>r.on(t,e))}),r.on("*",(...t)=>{e.exposeShortcut&&e.exposeShortcut(...t)})):r.emit("@shortcuts-error",`Context '${t}' does not exist`))}},listShortcuts:function(t,e){const n=e.shortcuts;return function(t=null){if(null!=t){let e=n[t];return null==e?null:Object.entries(e).map(([t,e])=>t)}return Object.keys(n).map(t=>{let e={};return e.context=t,e.shortcuts=Object.entries(n[t]).map(([t,e])=>t),e})}},load:function(t,e){const{shortcuts:n,plugins:o}=e,{API:{changeContext:r,getContext:i}}=t;return function(t){const e=i(),s=o.map(t=>t.getPrefix().toUpperCase());let c=!1;Object.entries(t).forEach(([t,r])=>{t===e&&(c=!0),n[t]={},Object.entries(r).forEach(([e,r])=>{let i=e,c=e.toUpperCase().trim(),u=s.map((t,e)=>c.startsWith(t)?e:null).filter(t=>null!==t);if(u.length){let t=u[0];i=o[t].shortcutName(e)}r instanceof Function&&(r=[r]),n[t][i]=r})}),c&&(r(),r(e))}},unload:function(t,e){const{currentContext:n,shortcuts:o}=e,{ev:r}=t;return function(t){n.name!==t?o[t]?delete o[t]:r.emit("shortcuts-error",`Context '${t}' does not exist`):r.emit("shortcuts-error",`Context '${t}' can't be removed during is current active context. Change the context first`)}}};function n(t){const e=t.toUpperCase(),n=/KEY\s*\:/i.test(e),o=e.indexOf(":");if(!n)return t;return`KEY:${e.slice(o+1).split(",").map(t=>t.trim()).map(t=>t.split("+").map(t=>t.trim()).sort().join("+")).join(",")}`}function o(t,e){let{shiftKey:n,altKey:o,ctrlKey:r}=t,i=e(),s=t.code.replace("Key","").replace("Digit",""),c=[];return r&&c.push("CTRL"),n&&c.push("SHIFT"),o&&c.push("ALT"),i.hasOwnProperty(s)?c.push(i[s].toUpperCase()):["ControlLeft","ControlRight","ShiftLeft","ShiftRight","AltLeft","AltRight","Meta"].includes(s)||c.push(s.toUpperCase()),c.sort()}function r(t,e){let n=0;const{regex:o}=t,{listenOptions:r,currentContext:{name:i},shortcuts:s}=e;return null==i?0:(Object.entries(s[i]).forEach(([t,e])=>{if(!o.test(t))return;n++;let i=t.slice(4).split(",").length;r.maxSequence<i&&(r.maxSequence=i)}),n)}function i(){return{ArrowLeft:"LEFT",ArrowUp:"UP",ArrowRight:"RIGHT",ArrowDown:"DOWN",Enter:"ENTER",NumpadEnter:"ENTER",Escape:"ESC",Backspace:"BACKSPACE",Space:"SPACE",Tab:"TAB",Backquote:"`",BracketLeft:"[",BracketRight:"]",Equal:"=",Slash:"/",Backslash:"\\",IntlBackslash:"`",F1:"F1",F2:"F2",F3:"F3",F4:"F4",F5:"F5",F6:"F6",F7:"F7",F8:"F8",F9:"F9",F10:"F10",F11:"F11",F12:"F12"}}function s(t,e,n){const{listenOptions:{clickTarget:o}}=e;let r=n;return r===document||r===document.body?null:r.dataset[o]||"A"===r.nodeName?r:s(t,e,r.parentNode)}function c(t){const e=t.toUpperCase(),n=/CLICK\s*\:/i.test(e),o=["LEFT","MIDDLE","RIGHT"],r=["ALT","SHIFT","CTRL"];let i=null,s=[],c=0,u=e.indexOf(":");return n?(e.slice(u+1).trim().split("-").map(t=>t.trim()).forEach(t=>{o.includes(t)?i=t:r.includes(t)?s.push(t):isNaN(t)||(c=t)}),`CLICK:${i}-${c}${s.length>0?"-":""}${s.sort().join("-")}`):t}function u(t,e){let{shiftKey:n,altKey:o,ctrlKey:r,key:i,button:s}=t,c=`CLICK:${["LEFT","MIDDLE","RIGHT"][s]}-${e}`,u=[];return r&&u.push("CTRL"),n&&u.push("SHIFT"),o&&u.push("ALT"),u.length>0?`${c}${u.length>0?"-":""}${u.sort().join("-")}`:`${c}`}function a(t,e){let n=0;const{regex:o}=t,{listenOptions:r,currentContext:{name:i},shortcuts:s}=e;return null==i?0:(Object.entries(s[i]).forEach(([t,e])=>{if(!o.test(t))return;n++;let[,i]=t.slice(6).split("-");r.maxClicks<i&&(r.maxClicks=i)}),n)}function l(t){const e=t.toUpperCase(),n=/FORM\s*\:/i.test(e),o=e.indexOf(":");if(!n)return t;return`FORM:${e.slice(o+1).trim()}`}function m(t,e){const{regex:n,_defaults:o,ev:r}=t,{currentContext:{name:i},shortcuts:s,callbacks:c}=e;let u=[],a=[],l=[];if(null==i)return!1;if(Object.entries(s[i]).forEach(([t,e])=>{n.test(t)&&("FORM:WATCH"===t&&(u=e),"FORM:DEFINE"===t&&(a=e),"FORM:ACTION"===t&&(l=e))}),0===l.length)return!1;let m=new Set;0===a.length&&(a=[o.define]),0===u.length&&(u=[o.watch]);let p=u.map(t=>t()).reduce((t,e)=>(t.push(e),t),[]);return e.watchList=document.querySelectorAll(p),e.watchList.forEach(t=>m.add(a[0](t))),e.typeFn=a[0]?a[0]:o.define,l.forEach(t=>{if(!(t instanceof Function))return console.warn("Warning: The 'form:action' should be a function."),!1;if(!(t()instanceof Array))return console.warn("Warning: The 'form:action' function should RETURN an array."),!1;t().forEach(({fn:t,type:n,timing:o,wait:i=0})=>{if(m.has(n)&&t instanceof Function){let e=`${n}/${o}`;const i=c.hasOwnProperty(e);i?c[e].push(t):c[e]=[t],i||r.on(e,(t,e)=>{e.forEach(e=>{e instanceof Function&&e(t)})})}"instant"===o&&(e.wait[`${n}`]=i)})}),Object.keys(e.callbacks).length>0}const p={watch:()=>"input, select, textarea, button, a",define:t=>"checkbox"===t.type||"radio"===t.type?"checkbox":"button"==t.type||"submit"==t.type?"button":"input"};exports.pluginClick=function(t,e,n){let{currentContext:o,shortcuts:r}=e,{inAPI:i}=t,l={ev:t.ev,_findTarget:s,_readClickEvent:u,mainDependencies:t,regex:/CLICK\s*\:/i},m={currentContext:o,shortcuts:r,listenOptions:{mouseWait:n.mouseWait?n.mouseWait:320,maxClicks:1,clickTarget:n.clickTarget?n.clickTarget:"click"}};i._normalizeWithPlugins(c);let p=function(t,e){const{ev:n,_findTarget:o,_readClickEvent:r,mainDependencies:i}=t,{listenOptions:s,currentContext:c}=e,{mouseWait:u}=s;let a=null,l=null,m=null,p=null,f=0;function h(){const t=r(l,f),e={target:a,targetProps:a?a.getBoundingClientRect():null,x:l.clientX,y:l.clientY,context:c.name,note:c.note,event:l,dependencies:i.extra,type:"click"};n.emit(t,e),m=null,p=null,a=null,l=null,f=0}function d(n){let r=s.maxClicks;return clearTimeout(m),p?(clearTimeout(p),void(p=setTimeout(()=>p=null,u))):(a=o(t,e,n.target),a&&a.dataset.hasOwnProperty("quickClick")&&(r=1),a&&"A"===a.tagName&&(r=1),l=n,f++,f>=r?(h(),void(r>1&&(p=setTimeout(()=>p=null,u)))):void(m=setTimeout(h,u)))}function g(n){let r=s.maxClicks;return clearTimeout(m),p?(clearTimeout(p),void(p=setTimeout(()=>p=null,u))):(a=o(t,e,n.target),a&&a.dataset.hasOwnProperty("quickClick")&&(r=1),a&&"A"===a.tagName&&(r=1),l=n,f++,f>=r?(h(),void(r>1&&(p=setTimeout(()=>p=null,u)))):void(m=setTimeout(h,u)))}return{start:function(){e.active||(window.addEventListener("contextmenu",g),document.addEventListener("click",d),e.active=!0)},stop:function(){e.active&&(window.removeEventListener("contextmenu",g),document.removeEventListener("click",d),e.active=!1)}}}(l,m),f=a(l,m);f>0&&p.start();let h={getPrefix:()=>"click",shortcutName:t=>c(t),contextChange:()=>{f=a(l,m),f<1&&p.stop(),f>0&&p.start()},mute:()=>p.stop(),unmute:()=>p.start(),destroy:()=>{p.stop(),m=null,h=null}};return Object.freeze(h),h},exports.pluginForm=function(t,e,n){let{currentContext:o,shortcuts:r}=e,{inAPI:i}=t,s={ev:t.ev,mainDependencies:t,regex:/FORM\s*\:/i,_defaults:p},c={currentContext:o,shortcuts:r,callbacks:{},typeFn:"",watchList:[],wait:{}};i._normalizeWithPlugins(l);let u=function(t,e){const{ev:n}=t;let o=null;function r(t,e,n,o){return{target:n.target,context:e.currentContext.name,note:e.currentContext.note,event:n,dependencies:t.mainDependencies.extra,type:o}}function i(o){const{callbacks:i,typeFn:s}=e,c=s(o.target),u=r(t,e,o,c),a=`${c}/in`;null!=i[a]&&n.emit(a,u,i[a])}function s(o){const{callbacks:i,typeFn:s}=e,c=r(t,e,o,"form-out"),u=`${s(o.target)}/out`;null!=i[u]&&n.emit(u,c,i[u])}function c(i){const{callbacks:s,typeFn:c}=e,u=r(t,e,i,"form-instant"),a=c(i.target),l=e.wait[`${a}`],m=`${a}/instant`;null!=s[m]&&(0!==l?(clearTimeout(o),o=setTimeout(()=>n.emit(m,u,s[m]),l)):n.emit(m,u,s[m]))}return{start:function(){e.active||(document.addEventListener("focusin",i),document.addEventListener("focusout",s),document.addEventListener("input",c),e.active=!0)},stop:function(){e.active&&(document.removeEventListener("focusin",i),document.removeEventListener("focusout",s),document.removeEventListener("input",c),e.active=!1)}}}(s,c);if(o.name){m(s,c)&&u.start()}let a={getPrefix:()=>"form",shortcutName:t=>l(t),contextChange:()=>{c.callbacks={},c.typeFn="",c.watchList=[],c.wait={},m(s,c)?u.start():u.stop()},mute:()=>u.stop(),unmute:()=>u.start(),destroy:()=>{u.stop(),c=null,a=null}};return Object.freeze(a),a},exports.pluginKey=function(t,e,s={}){let{currentContext:c,shortcuts:u,exposeShortcut:a}=e,{inAPI:l}=t,m={ev:t.ev,_specialChars:i,_readKeyEvent:o,mainDependencies:t,regex:/KEY\s*\:/i},p={currentContext:c,shortcuts:u,active:!1,listenOptions:{keyWait:s.keyWait?s.keyWait:480,maxSequence:1,keyIgnore:null},streamKeys:!(!s.streamKeys||"function"!=typeof s.streamKeys)&&s.streamKeys};l._normalizeWithPlugins(n);let f=function(t,e){const{ev:n,_specialChars:o,_readKeyEvent:r,mainDependencies:i}=t,{currentContext:s,streamKeys:c,listenOptions:u}=e,{keyWait:a}=u;let l=[],m=null,p=!0,f=!1;const h=()=>p=!1,d=()=>p=!0,g=()=>f=!0,x=()=>!1===p;function y(){let t=l.map(t=>[t.join("+")]);const e={wait:h,end:d,ignore:g,isWaiting:x,note:s.note,context:s.name,dependencies:i.extra,type:"key"};if(!p){let o=t.at(-1);n.emit(o,e),f&&(t=t.slice(0,-1),f=!1)}if(p){const o=`KEY:${t.join(",")}`;n.emit(o,e),l=[],m=null}}function C(e){if(clearTimeout(m),o().hasOwnProperty(e.code))return l.push(r(e,o)),c&&c({key:e.key,context:s.name,note:s.note,dependencies:t.extra}),u.keyIgnore?(clearTimeout(u.keyIgnore),void(u.keyIgnore=setTimeout(()=>u.keyIgnore=null,a))):p&&l.length===u.maxSequence?(y(),void(u.keyIgnore=setTimeout(()=>u.keyIgnore=null,a))):void(p?m=setTimeout(y,a):y())}function v(e){if(!o().hasOwnProperty(e.code)){if(clearTimeout(m),c&&c({key:e.key,context:s.name,note:s.note,dependencies:t.extra}),u.keyIgnore)return clearTimeout(u.keyIgnore),void(u.keyIgnore=setTimeout(()=>u.keyIgnore=null,a));if(l.push(r(e,o)),p&&l.length===u.maxSequence)return y(),void(u.keyIgnore=setTimeout(()=>u.keyIgnore=null,a));p?m=setTimeout(y,a):y()}}return{start:function(){e.active||(document.addEventListener("keydown",C),document.addEventListener("keypress",v),e.active=!0)},stop:function(){e.active&&(document.removeEventListener("keydown",C),document.removeEventListener("keypress",v),e.active=!1)}}}(m,p),h=r(m,p);h>0&&f.start();let d={getPrefix:()=>"key",shortcutName:t=>n(t),contextChange:t=>{h=r(m,p),h<1&&f.stop(),h>0&&f.start()},mute:()=>f.stop(),unmute:()=>f.start(),destroy:()=>{f.stop(),p=null,d=null}};return Object.freeze(d),d},exports.shortcuts=function(n={}){const o=t(),r={},i={},s={currentContext:{name:null,note:null},shortcuts:{},plugins:[],exposeShortcut:!(!n.onShortcut||"function"!=typeof n.onShortcut)&&n.onShortcut},c={ev:o,inAPI:r,API:i,extra:{}};return i.enablePlugin=(t,e={})=>{const n=t.name;if(-1===r._systemAction(n,"none")){let n;n=t(c,s,e),s.plugins.push(n)}},i.disablePlugin=t=>{const e=r._systemAction(t,"destroy");-1!==e&&(s.plugins=s.plugins.filter((t,n)=>n!==e))},i.mutePlugin=t=>r._systemAction(t,"mute"),i.unmutePlugin=t=>r._systemAction(t,"unmute"),i.getContext=()=>s.currentContext.name,i.getNote=()=>s.currentContext.note,i.setNote=(t=null)=>{"string"!=typeof t&&null!=t||(s.currentContext.note=t)},i.pause=(t="*")=>{let e=r._readShortcutWithPlugins(t);o.stop(e)},i.resume=(t="*")=>{const e=r._readShortcutWithPlugins(t);o.start(e)},i.emit=(t,...e)=>o.emit(r._readShortcutWithPlugins(t),...e),i.listContexts=()=>Object.keys(s.shortcuts),i.setDependencies=t=>c.extra={...c.extra,...t},i.getDependencies=()=>c.extra,Object.entries(e).forEach(([t,e])=>{t.startsWith("_")?r[t]=e(c,s):i[t]=e(c,s)}),i};
1
+ "use strict";var t=require("@peter.naydenov/notice");var e={_normalizeWithPlugins:function(t,e){return function(t){const n=e.shortcuts;Object.keys(n).forEach(e=>{Object.entries(n[e]).forEach(([o,r])=>{const i=t(o);i!==o&&(delete n[e][o],n[e][i]=r)})})}},_readShortcutWithPlugins:function(t,e){return function(n){const{inAPI:o}=t,r=n.split(":")[0].toLowerCase().trim(),i=o._systemAction(r,"none");let s=n;return-1!==i&&(s=e.plugins[i].shortcutName(n)),s}},_systemAction:function(t,e){return function(t,n,o=null){return e.plugins.findIndex(e=>e.getPrefix()===t&&(e[n]&&e[n](o),!0))}},changeContext:function(t,e){const{shortcuts:n,currentContext:o}=e,{ev:r}=t;return function(t=!1){const i=o.name;if(!t)return r.reset(),void(o.name=null);i!==t&&(n[t]?(n[i]&&r.reset(),o.name=t,e.plugins.forEach(e=>e.contextChange(t)),Object.entries(n[t]).forEach(([t,e])=>{e.forEach(e=>r.on(t,e))}),r.on("*",(...t)=>{e.exposeShortcut&&e.exposeShortcut(...t)})):r.emit("@shortcuts-error",`Context '${t}' does not exist`))}},listShortcuts:function(t,e){const n=e.shortcuts;return function(t=null){if(null!=t){let e=n[t];return null==e?null:Object.entries(e).map(([t,e])=>t)}return Object.keys(n).map(t=>{let e={};return e.context=t,e.shortcuts=Object.entries(n[t]).map(([t,e])=>t),e})}},load:function(t,e){const{shortcuts:n,plugins:o}=e,{API:{changeContext:r,getContext:i}}=t;return function(t){const e=i(),s=o.map(t=>t.getPrefix().toUpperCase());let c=!1;Object.entries(t).forEach(([t,r])=>{t===e&&(c=!0),n[t]={},Object.entries(r).forEach(([e,r])=>{let i=e,c=e.toUpperCase().trim(),u=s.map((t,e)=>c.startsWith(t)?e:null).filter(t=>null!==t);if(u.length){let t=u[0];i=o[t].shortcutName(e)}r instanceof Function&&(r=[r]),n[t][i]=r})}),c&&(r(),r(e))}},unload:function(t,e){const{currentContext:n,shortcuts:o}=e,{ev:r}=t;return function(t){n.name!==t?o[t]?delete o[t]:r.emit("shortcuts-error",`Context '${t}' does not exist`):r.emit("shortcuts-error",`Context '${t}' can't be removed during is current active context. Change the context first`)}}};function n(t){const e=t.toUpperCase(),n=/KEY\s*\:/i.test(e),o=e.indexOf(":");if(!n)return t;return`KEY:${e.slice(o+1).split(",").map(t=>t.trim()).map(t=>t.split("+").map(t=>t.trim()).sort().join("+")).join(",")}`}function o(t,e){let{shiftKey:n,altKey:o,ctrlKey:r}=t,i=e(),s=t.code.replace("Key","").replace("Digit",""),c=[];return r&&c.push("CTRL"),n&&c.push("SHIFT"),o&&c.push("ALT"),i.hasOwnProperty(s)?c.push(i[s].toUpperCase()):["ControlLeft","ControlRight","ShiftLeft","ShiftRight","AltLeft","AltRight","Meta"].includes(s)||c.push(s.toUpperCase()),c.sort()}function r(t,e){let n=0;const{regex:o}=t,{listenOptions:r,currentContext:{name:i},shortcuts:s}=e;return null==i?0:(Object.entries(s[i]).forEach(([t,e])=>{if(!o.test(t))return;n++;let i=t.slice(4).split(",").length;r.maxSequence<i&&(r.maxSequence=i)}),n)}function i(){return{ArrowLeft:"LEFT",ArrowUp:"UP",ArrowRight:"RIGHT",ArrowDown:"DOWN",Enter:"ENTER",NumpadEnter:"ENTER",Escape:"ESC",Backspace:"BACKSPACE",Space:"SPACE",Tab:"TAB",Backquote:"`",BracketLeft:"[",BracketRight:"]",Equal:"=",Slash:"/",Backslash:"\\",IntlBackslash:"`",F1:"F1",F2:"F2",F3:"F3",F4:"F4",F5:"F5",F6:"F6",F7:"F7",F8:"F8",F9:"F9",F10:"F10",F11:"F11",F12:"F12"}}function s(t,e,n){const{listenOptions:{clickTarget:o}}=e;let r=n;return r===document||r===document.body?null:r.dataset[o]||"A"===r.nodeName?r:s(t,e,r.parentNode)}function c(t){const e=t.toUpperCase(),n=/CLICK\s*\:/i.test(e),o=["LEFT","MIDDLE","RIGHT"],r=["ALT","SHIFT","CTRL"];let i=null,s=[],c=0,u=e.indexOf(":");return n?(e.slice(u+1).trim().split("-").map(t=>t.trim()).forEach(t=>{o.includes(t)?i=t:r.includes(t)?s.push(t):isNaN(t)||(c=t)}),`CLICK:${i}-${c}${s.length>0?"-":""}${s.sort().join("-")}`):t}function u(t,e){let{shiftKey:n,altKey:o,ctrlKey:r,key:i,button:s}=t,c=`CLICK:${["LEFT","MIDDLE","RIGHT"][s]}-${e}`,u=[];return r&&u.push("CTRL"),n&&u.push("SHIFT"),o&&u.push("ALT"),u.length>0?`${c}${u.length>0?"-":""}${u.sort().join("-")}`:`${c}`}function a(t,e){let n=0;const{regex:o}=t,{listenOptions:r,currentContext:{name:i},shortcuts:s}=e;return null==i?0:(Object.entries(s[i]).forEach(([t,e])=>{if(!o.test(t))return;n++;let[,i]=t.slice(6).split("-");r.maxClicks<i&&(r.maxClicks=i)}),n)}function l(t){const e=t.toUpperCase(),n=/FORM\s*\:/i.test(e),o=e.indexOf(":");if(!n)return t;return`FORM:${e.slice(o+1).trim()}`}function m(t,e){const{regex:n,_defaults:o,ev:r}=t,{currentContext:{name:i},shortcuts:s,callbacks:c}=e;let u=[],a=[],l=[];if(null==i)return!1;if(Object.entries(s[i]).forEach(([t,e])=>{n.test(t)&&("FORM:WATCH"===t&&(u=e),"FORM:DEFINE"===t&&(a=e),"FORM:ACTION"===t&&(l=e))}),0===l.length)return!1;let m=new Set;0===a.length&&(a=[o.define]),0===u.length&&(u=[o.watch]);let p=u.map(t=>t()).reduce((t,e)=>(t.push(e),t),[]);return e.watchList=document.querySelectorAll(p),e.watchList.forEach(t=>m.add(a[0](t))),e.typeFn=a[0]?a[0]:o.define,l.forEach(t=>{if(!(t instanceof Function))return console.warn("Warning: The 'form:action' should be a function."),!1;if(!(t()instanceof Array))return console.warn("Warning: The 'form:action' function should RETURN an array."),!1;t().forEach(({fn:t,type:n,timing:o,wait:i=0})=>{if(m.has(n)&&t instanceof Function){let e=`${n}/${o}`;const i=c.hasOwnProperty(e);i?c[e].push(t):c[e]=[t],i||r.on(e,(t,e)=>{e.forEach(e=>{e instanceof Function&&e(t)})})}"instant"===o&&(e.wait[`${n}`]=i)})}),Object.keys(e.callbacks).length>0}const p={watch:()=>"input, select, textarea, button, a",define:t=>"checkbox"===t.type||"radio"===t.type?"checkbox":"button"==t.type||"submit"==t.type?"button":"input"};exports.pluginClick=function(t,e,n){let{currentContext:o,shortcuts:r}=e,{inAPI:i}=t,l={ev:t.ev,_findTarget:s,_readClickEvent:u,mainDependencies:t,regex:/CLICK\s*\:/i},m={currentContext:o,active:!1,shortcuts:r,listenOptions:{mouseWait:n.mouseWait?n.mouseWait:320,maxClicks:1,clickTarget:n.clickTarget?n.clickTarget:"click"}};i._normalizeWithPlugins(c);let p=function(t,e){const{ev:n,_findTarget:o,_readClickEvent:r,mainDependencies:i}=t,{listenOptions:s,currentContext:c}=e,{mouseWait:u}=s;let a=null,l=null,m=null,p=null,f=0;function h(){const t=r(l,f),e={target:a,targetProps:a?a.getBoundingClientRect():null,x:l.clientX,y:l.clientY,context:c.name,note:c.note,event:l,dependencies:i.extra,type:"click"};n.emit(t,e),m=null,p=null,a=null,l=null,f=0}function d(n){let r=s.maxClicks;return clearTimeout(m),p?(clearTimeout(p),void(p=setTimeout(()=>p=null,u))):(a=o(t,e,n.target),a&&a.dataset.hasOwnProperty("quickClick")&&(r=1),a&&"A"===a.tagName&&(r=1),l=n,f++,f>=r?(h(),void(r>1&&(p=setTimeout(()=>p=null,u)))):void(m=setTimeout(h,u)))}function g(n){let r=s.maxClicks;return clearTimeout(m),p?(clearTimeout(p),void(p=setTimeout(()=>p=null,u))):(a=o(t,e,n.target),a&&a.dataset.hasOwnProperty("quickClick")&&(r=1),a&&"A"===a.tagName&&(r=1),l=n,f++,f>=r?(h(),void(r>1&&(p=setTimeout(()=>p=null,u)))):void(m=setTimeout(h,u)))}return{start:function(){e.active||(window.addEventListener("contextmenu",g),document.addEventListener("click",d),e.active=!0)},stop:function(){e.active&&(window.removeEventListener("contextmenu",g),document.removeEventListener("click",d),e.active=!1,m&&(clearTimeout(m),m=null),p&&(clearTimeout(p),p=null),f=0)}}}(l,m),f=a(l,m);f>0&&p.start();let h={getPrefix:()=>"click",shortcutName:t=>c(t),contextChange:()=>{f=a(l,m),f<1&&p.stop(),f>0&&p.start()},mute:()=>{p.stop()},unmute:()=>p.start(),destroy:()=>p.stop()};return Object.freeze(h),h},exports.pluginForm=function(t,e,n){let{currentContext:o,shortcuts:r}=e,{inAPI:i}=t,s={ev:t.ev,mainDependencies:t,regex:/FORM\s*\:/i,_defaults:p},c={currentContext:o,shortcuts:r,callbacks:{},typeFn:"",watchList:[],wait:{}};i._normalizeWithPlugins(l);let u=function(t,e){const{ev:n}=t;let o=null;function r(t,e,n,o){return{target:n.target,context:e.currentContext.name,note:e.currentContext.note,event:n,dependencies:t.mainDependencies.extra,type:o}}function i(o){const{callbacks:i,typeFn:s}=e,c=s(o.target),u=r(t,e,o,c),a=`${c}/in`;null!=i[a]&&n.emit(a,u,i[a])}function s(o){const{callbacks:i,typeFn:s}=e,c=r(t,e,o,"form-out"),u=`${s(o.target)}/out`;null!=i[u]&&n.emit(u,c,i[u])}function c(i){const{callbacks:s,typeFn:c}=e,u=r(t,e,i,"form-instant"),a=c(i.target),l=e.wait[`${a}`],m=`${a}/instant`;null!=s[m]&&(0!==l?(clearTimeout(o),o=setTimeout(()=>n.emit(m,u,s[m]),l)):n.emit(m,u,s[m]))}return{start:function(){e.active||(document.addEventListener("focusin",i),document.addEventListener("focusout",s),document.addEventListener("input",c),e.active=!0)},stop:function(){e.active&&(document.removeEventListener("focusin",i),document.removeEventListener("focusout",s),document.removeEventListener("input",c),e.active=!1)}}}(s,c);if(o.name){m(s,c)&&u.start()}let a={getPrefix:()=>"form",shortcutName:t=>l(t),contextChange:()=>{c.callbacks={},c.typeFn="",c.watchList=[],c.wait={},m(s,c)?u.start():u.stop()},mute:()=>u.stop(),unmute:()=>u.start(),destroy:()=>{u.stop()}};return Object.freeze(a),a},exports.pluginKey=function(t,e,s={}){let{currentContext:c,shortcuts:u,exposeShortcut:a}=e,{inAPI:l}=t,m={ev:t.ev,_specialChars:i,_readKeyEvent:o,mainDependencies:t,regex:/KEY\s*\:/i},p={currentContext:c,shortcuts:u,active:!1,listenOptions:{keyWait:s.keyWait?s.keyWait:480,maxSequence:1,keyIgnore:null},streamKeys:!(!s.streamKeys||"function"!=typeof s.streamKeys)&&s.streamKeys};l._normalizeWithPlugins(n);let f=function(t,e){const{ev:n,_specialChars:o,_readKeyEvent:r,mainDependencies:i}=t,{currentContext:s,streamKeys:c,listenOptions:u}=e,{keyWait:a}=u;let l=[],m=null,p=!0,f=!1;const h=()=>p=!1,d=()=>p=!0,g=()=>f=!0,x=()=>!1===p;function y(){let t=l.map(t=>[t.join("+")]);const e={wait:h,end:d,ignore:g,isWaiting:x,note:s.note,context:s.name,dependencies:i.extra,type:"key"};if(!p){let o=t.at(-1);n.emit(o,e),f&&(t=t.slice(0,-1),f=!1)}if(p){const o=`KEY:${t.join(",")}`;n.emit(o,e),l=[],m=null}}function C(e){if(clearTimeout(m),o().hasOwnProperty(e.code))return l.push(r(e,o)),c&&c({key:e.key,context:s.name,note:s.note,dependencies:t.extra}),u.keyIgnore?(clearTimeout(u.keyIgnore),void(u.keyIgnore=setTimeout(()=>u.keyIgnore=null,a))):p&&l.length===u.maxSequence?(y(),void(u.keyIgnore=setTimeout(()=>u.keyIgnore=null,a))):void(p?m=setTimeout(y,a):y())}function k(e){if(!o().hasOwnProperty(e.code)){if(clearTimeout(m),c&&c({key:e.key,context:s.name,note:s.note,dependencies:t.extra}),u.keyIgnore)return clearTimeout(u.keyIgnore),void(u.keyIgnore=setTimeout(()=>u.keyIgnore=null,a));if(l.push(r(e,o)),p&&l.length===u.maxSequence)return y(),void(u.keyIgnore=setTimeout(()=>u.keyIgnore=null,a));p?m=setTimeout(y,a):y()}}return{start:function(){e.active||(document.addEventListener("keydown",C),document.addEventListener("keypress",k),e.active=!0)},stop:function(){e.active&&(document.removeEventListener("keydown",C),document.removeEventListener("keypress",k),e.active=!1,m&&(clearTimeout(m),m=null),u.keyIgnore&&(clearTimeout(u.keyIgnore),u.keyIgnore=null),l=[],p=!0,f=!1)}}}(m,p),h=r(m,p);h>0&&f.start();let d={getPrefix:()=>"key",shortcutName:t=>n(t),contextChange:t=>{h=r(m,p),h<1&&f.stop(),h>0&&f.start()},mute:()=>f.stop(),unmute:()=>f.start(),destroy:()=>f.stop()};return Object.freeze(d),d},exports.shortcuts=function(n={}){let o={},r={};const i=t(),s={currentContext:{name:null,note:null},shortcuts:{},plugins:[],exposeShortcut:!(!n.onShortcut||"function"!=typeof n.onShortcut)&&n.onShortcut};let c={ev:i,inAPI:o,API:r,extra:{}};return r.enablePlugin=(t,e={})=>{const n=t.name.replace("plugin","").toLowerCase();if(-1===o._systemAction(n,"none")){let n=t(c,s,e);s.plugins.push(n)}},r.disablePlugin=t=>{const e=o._systemAction(t,"destroy");-1!==e&&(s.plugins=s.plugins.filter((t,n)=>n!==e))},r.mutePlugin=t=>o._systemAction(t,"mute"),r.unmutePlugin=t=>o._systemAction(t,"unmute"),r.getContext=()=>s.currentContext.name,r.getNote=()=>s.currentContext.note,r.setNote=(t=null)=>{"string"!=typeof t&&null!=t||(s.currentContext.note=t)},r.pause=(t="*")=>{let e=o._readShortcutWithPlugins(t);i.stop(e)},r.resume=(t="*")=>{const e=o._readShortcutWithPlugins(t);i.start(e)},r.emit=(t,...e)=>i.emit(o._readShortcutWithPlugins(t),...e),r.listContexts=()=>Object.keys(s.shortcuts),r.setDependencies=t=>c.extra={...c.extra,...t},r.getDependencies=()=>c.extra,r.reset=function(){i.reset(),r.changeContext(),s.plugins.forEach(t=>t.destroy()),r.listContexts().map(t=>r.unload(t)),c.extra={},s.exposeShortcut=null},Object.entries(e).forEach(([t,e])=>{t.startsWith("_")?o[t]=e(c,s):r[t]=e(c,s)}),r};
@@ -1 +1 @@
1
- import t from"@peter.naydenov/notice";var e={_normalizeWithPlugins:function(t,e){return function(t){const n=e.shortcuts;Object.keys(n).forEach(e=>{Object.entries(n[e]).forEach(([o,r])=>{const i=t(o);i!==o&&(delete n[e][o],n[e][i]=r)})})}},_readShortcutWithPlugins:function(t,e){return function(n){const{inAPI:o}=t,r=n.split(":")[0],i=o._systemAction(r,"none");let s=n;return-1!==i&&(s=e.plugins[i].shortcutName(n)),s}},_systemAction:function(t,e){return function(t,n,o=null){return e.plugins.findIndex(e=>e.getPrefix()===t&&(e[n]&&e[n](o),!0))}},changeContext:function(t,e){const{shortcuts:n,currentContext:o}=e,{ev:r}=t;return function(t=!1){const i=o.name;if(!t)return r.reset(),void(o.name=null);i!==t&&(n[t]?(n[i]&&r.reset(),o.name=t,e.plugins.forEach(e=>e.contextChange(t)),Object.entries(n[t]).forEach(([t,e])=>{e.forEach(e=>r.on(t,e))}),r.on("*",(...t)=>{e.exposeShortcut&&e.exposeShortcut(...t)})):r.emit("@shortcuts-error",`Context '${t}' does not exist`))}},listShortcuts:function(t,e){const n=e.shortcuts;return function(t=null){if(null!=t){let e=n[t];return null==e?null:Object.entries(e).map(([t,e])=>t)}return Object.keys(n).map(t=>{let e={};return e.context=t,e.shortcuts=Object.entries(n[t]).map(([t,e])=>t),e})}},load:function(t,e){const{shortcuts:n,plugins:o}=e,{API:{changeContext:r,getContext:i}}=t;return function(t){const e=i(),s=o.map(t=>t.getPrefix().toUpperCase());let c=!1;Object.entries(t).forEach(([t,r])=>{t===e&&(c=!0),n[t]={},Object.entries(r).forEach(([e,r])=>{let i=e,c=e.toUpperCase().trim(),u=s.map((t,e)=>c.startsWith(t)?e:null).filter(t=>null!==t);if(u.length){let t=u[0];i=o[t].shortcutName(e)}r instanceof Function&&(r=[r]),n[t][i]=r})}),c&&(r(),r(e))}},unload:function(t,e){const{currentContext:n,shortcuts:o}=e,{ev:r}=t;return function(t){n.name!==t?o[t]?delete o[t]:r.emit("shortcuts-error",`Context '${t}' does not exist`):r.emit("shortcuts-error",`Context '${t}' can't be removed during is current active context. Change the context first`)}}};function n(t){const e=t.toUpperCase(),n=/KEY\s*\:/i.test(e),o=e.indexOf(":");if(!n)return t;return`KEY:${e.slice(o+1).split(",").map(t=>t.trim()).map(t=>t.split("+").map(t=>t.trim()).sort().join("+")).join(",")}`}function o(t,e){let{shiftKey:n,altKey:o,ctrlKey:r}=t,i=e(),s=t.code.replace("Key","").replace("Digit",""),c=[];return r&&c.push("CTRL"),n&&c.push("SHIFT"),o&&c.push("ALT"),i.hasOwnProperty(s)?c.push(i[s].toUpperCase()):["ControlLeft","ControlRight","ShiftLeft","ShiftRight","AltLeft","AltRight","Meta"].includes(s)||c.push(s.toUpperCase()),c.sort()}function r(t,e){let n=0;const{regex:o}=t,{listenOptions:r,currentContext:{name:i},shortcuts:s}=e;return null==i?0:(Object.entries(s[i]).forEach(([t,e])=>{if(!o.test(t))return;n++;let i=t.slice(4).split(",").length;r.maxSequence<i&&(r.maxSequence=i)}),n)}function i(){return{ArrowLeft:"LEFT",ArrowUp:"UP",ArrowRight:"RIGHT",ArrowDown:"DOWN",Enter:"ENTER",NumpadEnter:"ENTER",Escape:"ESC",Backspace:"BACKSPACE",Space:"SPACE",Tab:"TAB",Backquote:"`",BracketLeft:"[",BracketRight:"]",Equal:"=",Slash:"/",Backslash:"\\",IntlBackslash:"`",F1:"F1",F2:"F2",F3:"F3",F4:"F4",F5:"F5",F6:"F6",F7:"F7",F8:"F8",F9:"F9",F10:"F10",F11:"F11",F12:"F12"}}function s(t,e,s={}){let{currentContext:c,shortcuts:u,exposeShortcut:a}=e,{inAPI:l}=t,m={ev:t.ev,_specialChars:i,_readKeyEvent:o,mainDependencies:t,regex:/KEY\s*\:/i},f={currentContext:c,shortcuts:u,active:!1,listenOptions:{keyWait:s.keyWait?s.keyWait:480,maxSequence:1,keyIgnore:null},streamKeys:!(!s.streamKeys||"function"!=typeof s.streamKeys)&&s.streamKeys};l._normalizeWithPlugins(n);let p=function(t,e){const{ev:n,_specialChars:o,_readKeyEvent:r,mainDependencies:i}=t,{currentContext:s,streamKeys:c,listenOptions:u}=e,{keyWait:a}=u;let l=[],m=null,f=!0,p=!1;const h=()=>f=!1,d=()=>f=!0,g=()=>p=!0,x=()=>!1===f;function y(){let t=l.map(t=>[t.join("+")]);const e={wait:h,end:d,ignore:g,isWaiting:x,note:s.note,context:s.name,dependencies:i.extra,type:"key"};if(!f){let o=t.at(-1);n.emit(o,e),p&&(t=t.slice(0,-1),p=!1)}if(f){const o=`KEY:${t.join(",")}`;n.emit(o,e),l=[],m=null}}function C(e){if(clearTimeout(m),o().hasOwnProperty(e.code))return l.push(r(e,o)),c&&c({key:e.key,context:s.name,note:s.note,dependencies:t.extra}),u.keyIgnore?(clearTimeout(u.keyIgnore),void(u.keyIgnore=setTimeout(()=>u.keyIgnore=null,a))):f&&l.length===u.maxSequence?(y(),void(u.keyIgnore=setTimeout(()=>u.keyIgnore=null,a))):void(f?m=setTimeout(y,a):y())}function v(e){if(!o().hasOwnProperty(e.code)){if(clearTimeout(m),c&&c({key:e.key,context:s.name,note:s.note,dependencies:t.extra}),u.keyIgnore)return clearTimeout(u.keyIgnore),void(u.keyIgnore=setTimeout(()=>u.keyIgnore=null,a));if(l.push(r(e,o)),f&&l.length===u.maxSequence)return y(),void(u.keyIgnore=setTimeout(()=>u.keyIgnore=null,a));f?m=setTimeout(y,a):y()}}return{start:function(){e.active||(document.addEventListener("keydown",C),document.addEventListener("keypress",v),e.active=!0)},stop:function(){e.active&&(document.removeEventListener("keydown",C),document.removeEventListener("keypress",v),e.active=!1)}}}(m,f),h=r(m,f);h>0&&p.start();let d={getPrefix:()=>"key",shortcutName:t=>n(t),contextChange:t=>{h=r(m,f),h<1&&p.stop(),h>0&&p.start()},mute:()=>p.stop(),unmute:()=>p.start(),destroy:()=>{p.stop(),f=null,d=null}};return Object.freeze(d),d}function c(t,e,n){const{listenOptions:{clickTarget:o}}=e;let r=n;return r===document||r===document.body?null:r.dataset[o]||"A"===r.nodeName?r:c(t,e,r.parentNode)}function u(t){const e=t.toUpperCase(),n=/CLICK\s*\:/i.test(e),o=["LEFT","MIDDLE","RIGHT"],r=["ALT","SHIFT","CTRL"];let i=null,s=[],c=0,u=e.indexOf(":");return n?(e.slice(u+1).trim().split("-").map(t=>t.trim()).forEach(t=>{o.includes(t)?i=t:r.includes(t)?s.push(t):isNaN(t)||(c=t)}),`CLICK:${i}-${c}${s.length>0?"-":""}${s.sort().join("-")}`):t}function a(t,e){let{shiftKey:n,altKey:o,ctrlKey:r,key:i,button:s}=t,c=`CLICK:${["LEFT","MIDDLE","RIGHT"][s]}-${e}`,u=[];return r&&u.push("CTRL"),n&&u.push("SHIFT"),o&&u.push("ALT"),u.length>0?`${c}${u.length>0?"-":""}${u.sort().join("-")}`:`${c}`}function l(t,e){let n=0;const{regex:o}=t,{listenOptions:r,currentContext:{name:i},shortcuts:s}=e;return null==i?0:(Object.entries(s[i]).forEach(([t,e])=>{if(!o.test(t))return;n++;let[,i]=t.slice(6).split("-");r.maxClicks<i&&(r.maxClicks=i)}),n)}function m(t,e,n){let{currentContext:o,shortcuts:r}=e,{inAPI:i}=t,s={ev:t.ev,_findTarget:c,_readClickEvent:a,mainDependencies:t,regex:/CLICK\s*\:/i},m={currentContext:o,shortcuts:r,listenOptions:{mouseWait:n.mouseWait?n.mouseWait:320,maxClicks:1,clickTarget:n.clickTarget?n.clickTarget:"click"}};i._normalizeWithPlugins(u);let f=function(t,e){const{ev:n,_findTarget:o,_readClickEvent:r,mainDependencies:i}=t,{listenOptions:s,currentContext:c}=e,{mouseWait:u}=s;let a=null,l=null,m=null,f=null,p=0;function h(){const t=r(l,p),e={target:a,targetProps:a?a.getBoundingClientRect():null,x:l.clientX,y:l.clientY,context:c.name,note:c.note,event:l,dependencies:i.extra,type:"click"};n.emit(t,e),m=null,f=null,a=null,l=null,p=0}function d(n){let r=s.maxClicks;return clearTimeout(m),f?(clearTimeout(f),void(f=setTimeout(()=>f=null,u))):(a=o(t,e,n.target),a&&a.dataset.hasOwnProperty("quickClick")&&(r=1),a&&"A"===a.tagName&&(r=1),l=n,p++,p>=r?(h(),void(r>1&&(f=setTimeout(()=>f=null,u)))):void(m=setTimeout(h,u)))}function g(n){let r=s.maxClicks;return clearTimeout(m),f?(clearTimeout(f),void(f=setTimeout(()=>f=null,u))):(a=o(t,e,n.target),a&&a.dataset.hasOwnProperty("quickClick")&&(r=1),a&&"A"===a.tagName&&(r=1),l=n,p++,p>=r?(h(),void(r>1&&(f=setTimeout(()=>f=null,u)))):void(m=setTimeout(h,u)))}return{start:function(){e.active||(window.addEventListener("contextmenu",g),document.addEventListener("click",d),e.active=!0)},stop:function(){e.active&&(window.removeEventListener("contextmenu",g),document.removeEventListener("click",d),e.active=!1)}}}(s,m),p=l(s,m);p>0&&f.start();let h={getPrefix:()=>"click",shortcutName:t=>u(t),contextChange:()=>{p=l(s,m),p<1&&f.stop(),p>0&&f.start()},mute:()=>f.stop(),unmute:()=>f.start(),destroy:()=>{f.stop(),m=null,h=null}};return Object.freeze(h),h}function f(t){const e=t.toUpperCase(),n=/FORM\s*\:/i.test(e),o=e.indexOf(":");if(!n)return t;return`FORM:${e.slice(o+1).trim()}`}function p(t,e){const{regex:n,_defaults:o,ev:r}=t,{currentContext:{name:i},shortcuts:s,callbacks:c}=e;let u=[],a=[],l=[];if(null==i)return!1;if(Object.entries(s[i]).forEach(([t,e])=>{n.test(t)&&("FORM:WATCH"===t&&(u=e),"FORM:DEFINE"===t&&(a=e),"FORM:ACTION"===t&&(l=e))}),0===l.length)return!1;let m=new Set;0===a.length&&(a=[o.define]),0===u.length&&(u=[o.watch]);let f=u.map(t=>t()).reduce((t,e)=>(t.push(e),t),[]);return e.watchList=document.querySelectorAll(f),e.watchList.forEach(t=>m.add(a[0](t))),e.typeFn=a[0]?a[0]:o.define,l.forEach(t=>{if(!(t instanceof Function))return console.warn("Warning: The 'form:action' should be a function."),!1;if(!(t()instanceof Array))return console.warn("Warning: The 'form:action' function should RETURN an array."),!1;t().forEach(({fn:t,type:n,timing:o,wait:i=0})=>{if(m.has(n)&&t instanceof Function){let e=`${n}/${o}`;const i=c.hasOwnProperty(e);i?c[e].push(t):c[e]=[t],i||r.on(e,(t,e)=>{e.forEach(e=>{e instanceof Function&&e(t)})})}"instant"===o&&(e.wait[`${n}`]=i)})}),Object.keys(e.callbacks).length>0}const h={watch:()=>"input, select, textarea, button, a",define:t=>"checkbox"===t.type||"radio"===t.type?"checkbox":"button"==t.type||"submit"==t.type?"button":"input"};function d(t,e,n){let{currentContext:o,shortcuts:r}=e,{inAPI:i}=t,s={ev:t.ev,mainDependencies:t,regex:/FORM\s*\:/i,_defaults:h},c={currentContext:o,shortcuts:r,callbacks:{},typeFn:"",watchList:[],wait:{}};i._normalizeWithPlugins(f);let u=function(t,e){const{ev:n}=t;let o=null;function r(t,e,n,o){return{target:n.target,context:e.currentContext.name,note:e.currentContext.note,event:n,dependencies:t.mainDependencies.extra,type:o}}function i(o){const{callbacks:i,typeFn:s}=e,c=s(o.target),u=r(t,e,o,c),a=`${c}/in`;null!=i[a]&&n.emit(a,u,i[a])}function s(o){const{callbacks:i,typeFn:s}=e,c=r(t,e,o,"form-out"),u=`${s(o.target)}/out`;null!=i[u]&&n.emit(u,c,i[u])}function c(i){const{callbacks:s,typeFn:c}=e,u=r(t,e,i,"form-instant"),a=c(i.target),l=e.wait[`${a}`],m=`${a}/instant`;null!=s[m]&&(0!==l?(clearTimeout(o),o=setTimeout(()=>n.emit(m,u,s[m]),l)):n.emit(m,u,s[m]))}return{start:function(){e.active||(document.addEventListener("focusin",i),document.addEventListener("focusout",s),document.addEventListener("input",c),e.active=!0)},stop:function(){e.active&&(document.removeEventListener("focusin",i),document.removeEventListener("focusout",s),document.removeEventListener("input",c),e.active=!1)}}}(s,c);if(o.name){p(s,c)&&u.start()}let a={getPrefix:()=>"form",shortcutName:t=>f(t),contextChange:()=>{c.callbacks={},c.typeFn="",c.watchList=[],c.wait={},p(s,c)?u.start():u.stop()},mute:()=>u.stop(),unmute:()=>u.start(),destroy:()=>{u.stop(),c=null,a=null}};return Object.freeze(a),a}function g(n={}){const o=t(),r={},i={},s={currentContext:{name:null,note:null},shortcuts:{},plugins:[],exposeShortcut:!(!n.onShortcut||"function"!=typeof n.onShortcut)&&n.onShortcut},c={ev:o,inAPI:r,API:i,extra:{}};return i.enablePlugin=(t,e={})=>{const n=t.name;if(-1===r._systemAction(n,"none")){let n;n=t(c,s,e),s.plugins.push(n)}},i.disablePlugin=t=>{const e=r._systemAction(t,"destroy");-1!==e&&(s.plugins=s.plugins.filter((t,n)=>n!==e))},i.mutePlugin=t=>r._systemAction(t,"mute"),i.unmutePlugin=t=>r._systemAction(t,"unmute"),i.getContext=()=>s.currentContext.name,i.getNote=()=>s.currentContext.note,i.setNote=(t=null)=>{"string"!=typeof t&&null!=t||(s.currentContext.note=t)},i.pause=(t="*")=>{let e=r._readShortcutWithPlugins(t);o.stop(e)},i.resume=(t="*")=>{const e=r._readShortcutWithPlugins(t);o.start(e)},i.emit=(t,...e)=>o.emit(r._readShortcutWithPlugins(t),...e),i.listContexts=()=>Object.keys(s.shortcuts),i.setDependencies=t=>c.extra={...c.extra,...t},i.getDependencies=()=>c.extra,Object.entries(e).forEach(([t,e])=>{t.startsWith("_")?r[t]=e(c,s):i[t]=e(c,s)}),i}export{m as pluginClick,d as pluginForm,s as pluginKey,g as shortcuts};
1
+ import t from"@peter.naydenov/notice";var e={_normalizeWithPlugins:function(t,e){return function(t){const n=e.shortcuts;Object.keys(n).forEach(e=>{Object.entries(n[e]).forEach(([o,r])=>{const i=t(o);i!==o&&(delete n[e][o],n[e][i]=r)})})}},_readShortcutWithPlugins:function(t,e){return function(n){const{inAPI:o}=t,r=n.split(":")[0].toLowerCase().trim(),i=o._systemAction(r,"none");let s=n;return-1!==i&&(s=e.plugins[i].shortcutName(n)),s}},_systemAction:function(t,e){return function(t,n,o=null){return e.plugins.findIndex(e=>e.getPrefix()===t&&(e[n]&&e[n](o),!0))}},changeContext:function(t,e){const{shortcuts:n,currentContext:o}=e,{ev:r}=t;return function(t=!1){const i=o.name;if(!t)return r.reset(),void(o.name=null);i!==t&&(n[t]?(n[i]&&r.reset(),o.name=t,e.plugins.forEach(e=>e.contextChange(t)),Object.entries(n[t]).forEach(([t,e])=>{e.forEach(e=>r.on(t,e))}),r.on("*",(...t)=>{e.exposeShortcut&&e.exposeShortcut(...t)})):r.emit("@shortcuts-error",`Context '${t}' does not exist`))}},listShortcuts:function(t,e){const n=e.shortcuts;return function(t=null){if(null!=t){let e=n[t];return null==e?null:Object.entries(e).map(([t,e])=>t)}return Object.keys(n).map(t=>{let e={};return e.context=t,e.shortcuts=Object.entries(n[t]).map(([t,e])=>t),e})}},load:function(t,e){const{shortcuts:n,plugins:o}=e,{API:{changeContext:r,getContext:i}}=t;return function(t){const e=i(),s=o.map(t=>t.getPrefix().toUpperCase());let c=!1;Object.entries(t).forEach(([t,r])=>{t===e&&(c=!0),n[t]={},Object.entries(r).forEach(([e,r])=>{let i=e,c=e.toUpperCase().trim(),u=s.map((t,e)=>c.startsWith(t)?e:null).filter(t=>null!==t);if(u.length){let t=u[0];i=o[t].shortcutName(e)}r instanceof Function&&(r=[r]),n[t][i]=r})}),c&&(r(),r(e))}},unload:function(t,e){const{currentContext:n,shortcuts:o}=e,{ev:r}=t;return function(t){n.name!==t?o[t]?delete o[t]:r.emit("shortcuts-error",`Context '${t}' does not exist`):r.emit("shortcuts-error",`Context '${t}' can't be removed during is current active context. Change the context first`)}}};function n(t){const e=t.toUpperCase(),n=/KEY\s*\:/i.test(e),o=e.indexOf(":");if(!n)return t;return`KEY:${e.slice(o+1).split(",").map(t=>t.trim()).map(t=>t.split("+").map(t=>t.trim()).sort().join("+")).join(",")}`}function o(t,e){let{shiftKey:n,altKey:o,ctrlKey:r}=t,i=e(),s=t.code.replace("Key","").replace("Digit",""),c=[];return r&&c.push("CTRL"),n&&c.push("SHIFT"),o&&c.push("ALT"),i.hasOwnProperty(s)?c.push(i[s].toUpperCase()):["ControlLeft","ControlRight","ShiftLeft","ShiftRight","AltLeft","AltRight","Meta"].includes(s)||c.push(s.toUpperCase()),c.sort()}function r(t,e){let n=0;const{regex:o}=t,{listenOptions:r,currentContext:{name:i},shortcuts:s}=e;return null==i?0:(Object.entries(s[i]).forEach(([t,e])=>{if(!o.test(t))return;n++;let i=t.slice(4).split(",").length;r.maxSequence<i&&(r.maxSequence=i)}),n)}function i(){return{ArrowLeft:"LEFT",ArrowUp:"UP",ArrowRight:"RIGHT",ArrowDown:"DOWN",Enter:"ENTER",NumpadEnter:"ENTER",Escape:"ESC",Backspace:"BACKSPACE",Space:"SPACE",Tab:"TAB",Backquote:"`",BracketLeft:"[",BracketRight:"]",Equal:"=",Slash:"/",Backslash:"\\",IntlBackslash:"`",F1:"F1",F2:"F2",F3:"F3",F4:"F4",F5:"F5",F6:"F6",F7:"F7",F8:"F8",F9:"F9",F10:"F10",F11:"F11",F12:"F12"}}function s(t,e,s={}){let{currentContext:c,shortcuts:u,exposeShortcut:a}=e,{inAPI:l}=t,m={ev:t.ev,_specialChars:i,_readKeyEvent:o,mainDependencies:t,regex:/KEY\s*\:/i},f={currentContext:c,shortcuts:u,active:!1,listenOptions:{keyWait:s.keyWait?s.keyWait:480,maxSequence:1,keyIgnore:null},streamKeys:!(!s.streamKeys||"function"!=typeof s.streamKeys)&&s.streamKeys};l._normalizeWithPlugins(n);let p=function(t,e){const{ev:n,_specialChars:o,_readKeyEvent:r,mainDependencies:i}=t,{currentContext:s,streamKeys:c,listenOptions:u}=e,{keyWait:a}=u;let l=[],m=null,f=!0,p=!1;const h=()=>f=!1,d=()=>f=!0,g=()=>p=!0,x=()=>!1===f;function y(){let t=l.map(t=>[t.join("+")]);const e={wait:h,end:d,ignore:g,isWaiting:x,note:s.note,context:s.name,dependencies:i.extra,type:"key"};if(!f){let o=t.at(-1);n.emit(o,e),p&&(t=t.slice(0,-1),p=!1)}if(f){const o=`KEY:${t.join(",")}`;n.emit(o,e),l=[],m=null}}function C(e){if(clearTimeout(m),o().hasOwnProperty(e.code))return l.push(r(e,o)),c&&c({key:e.key,context:s.name,note:s.note,dependencies:t.extra}),u.keyIgnore?(clearTimeout(u.keyIgnore),void(u.keyIgnore=setTimeout(()=>u.keyIgnore=null,a))):f&&l.length===u.maxSequence?(y(),void(u.keyIgnore=setTimeout(()=>u.keyIgnore=null,a))):void(f?m=setTimeout(y,a):y())}function k(e){if(!o().hasOwnProperty(e.code)){if(clearTimeout(m),c&&c({key:e.key,context:s.name,note:s.note,dependencies:t.extra}),u.keyIgnore)return clearTimeout(u.keyIgnore),void(u.keyIgnore=setTimeout(()=>u.keyIgnore=null,a));if(l.push(r(e,o)),f&&l.length===u.maxSequence)return y(),void(u.keyIgnore=setTimeout(()=>u.keyIgnore=null,a));f?m=setTimeout(y,a):y()}}return{start:function(){e.active||(document.addEventListener("keydown",C),document.addEventListener("keypress",k),e.active=!0)},stop:function(){e.active&&(document.removeEventListener("keydown",C),document.removeEventListener("keypress",k),e.active=!1,m&&(clearTimeout(m),m=null),u.keyIgnore&&(clearTimeout(u.keyIgnore),u.keyIgnore=null),l=[],f=!0,p=!1)}}}(m,f),h=r(m,f);h>0&&p.start();let d={getPrefix:()=>"key",shortcutName:t=>n(t),contextChange:t=>{h=r(m,f),h<1&&p.stop(),h>0&&p.start()},mute:()=>p.stop(),unmute:()=>p.start(),destroy:()=>p.stop()};return Object.freeze(d),d}function c(t,e,n){const{listenOptions:{clickTarget:o}}=e;let r=n;return r===document||r===document.body?null:r.dataset[o]||"A"===r.nodeName?r:c(t,e,r.parentNode)}function u(t){const e=t.toUpperCase(),n=/CLICK\s*\:/i.test(e),o=["LEFT","MIDDLE","RIGHT"],r=["ALT","SHIFT","CTRL"];let i=null,s=[],c=0,u=e.indexOf(":");return n?(e.slice(u+1).trim().split("-").map(t=>t.trim()).forEach(t=>{o.includes(t)?i=t:r.includes(t)?s.push(t):isNaN(t)||(c=t)}),`CLICK:${i}-${c}${s.length>0?"-":""}${s.sort().join("-")}`):t}function a(t,e){let{shiftKey:n,altKey:o,ctrlKey:r,key:i,button:s}=t,c=`CLICK:${["LEFT","MIDDLE","RIGHT"][s]}-${e}`,u=[];return r&&u.push("CTRL"),n&&u.push("SHIFT"),o&&u.push("ALT"),u.length>0?`${c}${u.length>0?"-":""}${u.sort().join("-")}`:`${c}`}function l(t,e){let n=0;const{regex:o}=t,{listenOptions:r,currentContext:{name:i},shortcuts:s}=e;return null==i?0:(Object.entries(s[i]).forEach(([t,e])=>{if(!o.test(t))return;n++;let[,i]=t.slice(6).split("-");r.maxClicks<i&&(r.maxClicks=i)}),n)}function m(t,e,n){let{currentContext:o,shortcuts:r}=e,{inAPI:i}=t,s={ev:t.ev,_findTarget:c,_readClickEvent:a,mainDependencies:t,regex:/CLICK\s*\:/i},m={currentContext:o,active:!1,shortcuts:r,listenOptions:{mouseWait:n.mouseWait?n.mouseWait:320,maxClicks:1,clickTarget:n.clickTarget?n.clickTarget:"click"}};i._normalizeWithPlugins(u);let f=function(t,e){const{ev:n,_findTarget:o,_readClickEvent:r,mainDependencies:i}=t,{listenOptions:s,currentContext:c}=e,{mouseWait:u}=s;let a=null,l=null,m=null,f=null,p=0;function h(){const t=r(l,p),e={target:a,targetProps:a?a.getBoundingClientRect():null,x:l.clientX,y:l.clientY,context:c.name,note:c.note,event:l,dependencies:i.extra,type:"click"};n.emit(t,e),m=null,f=null,a=null,l=null,p=0}function d(n){let r=s.maxClicks;return clearTimeout(m),f?(clearTimeout(f),void(f=setTimeout(()=>f=null,u))):(a=o(t,e,n.target),a&&a.dataset.hasOwnProperty("quickClick")&&(r=1),a&&"A"===a.tagName&&(r=1),l=n,p++,p>=r?(h(),void(r>1&&(f=setTimeout(()=>f=null,u)))):void(m=setTimeout(h,u)))}function g(n){let r=s.maxClicks;return clearTimeout(m),f?(clearTimeout(f),void(f=setTimeout(()=>f=null,u))):(a=o(t,e,n.target),a&&a.dataset.hasOwnProperty("quickClick")&&(r=1),a&&"A"===a.tagName&&(r=1),l=n,p++,p>=r?(h(),void(r>1&&(f=setTimeout(()=>f=null,u)))):void(m=setTimeout(h,u)))}return{start:function(){e.active||(window.addEventListener("contextmenu",g),document.addEventListener("click",d),e.active=!0)},stop:function(){e.active&&(window.removeEventListener("contextmenu",g),document.removeEventListener("click",d),e.active=!1,m&&(clearTimeout(m),m=null),f&&(clearTimeout(f),f=null),p=0)}}}(s,m),p=l(s,m);p>0&&f.start();let h={getPrefix:()=>"click",shortcutName:t=>u(t),contextChange:()=>{p=l(s,m),p<1&&f.stop(),p>0&&f.start()},mute:()=>{f.stop()},unmute:()=>f.start(),destroy:()=>f.stop()};return Object.freeze(h),h}function f(t){const e=t.toUpperCase(),n=/FORM\s*\:/i.test(e),o=e.indexOf(":");if(!n)return t;return`FORM:${e.slice(o+1).trim()}`}function p(t,e){const{regex:n,_defaults:o,ev:r}=t,{currentContext:{name:i},shortcuts:s,callbacks:c}=e;let u=[],a=[],l=[];if(null==i)return!1;if(Object.entries(s[i]).forEach(([t,e])=>{n.test(t)&&("FORM:WATCH"===t&&(u=e),"FORM:DEFINE"===t&&(a=e),"FORM:ACTION"===t&&(l=e))}),0===l.length)return!1;let m=new Set;0===a.length&&(a=[o.define]),0===u.length&&(u=[o.watch]);let f=u.map(t=>t()).reduce((t,e)=>(t.push(e),t),[]);return e.watchList=document.querySelectorAll(f),e.watchList.forEach(t=>m.add(a[0](t))),e.typeFn=a[0]?a[0]:o.define,l.forEach(t=>{if(!(t instanceof Function))return console.warn("Warning: The 'form:action' should be a function."),!1;if(!(t()instanceof Array))return console.warn("Warning: The 'form:action' function should RETURN an array."),!1;t().forEach(({fn:t,type:n,timing:o,wait:i=0})=>{if(m.has(n)&&t instanceof Function){let e=`${n}/${o}`;const i=c.hasOwnProperty(e);i?c[e].push(t):c[e]=[t],i||r.on(e,(t,e)=>{e.forEach(e=>{e instanceof Function&&e(t)})})}"instant"===o&&(e.wait[`${n}`]=i)})}),Object.keys(e.callbacks).length>0}const h={watch:()=>"input, select, textarea, button, a",define:t=>"checkbox"===t.type||"radio"===t.type?"checkbox":"button"==t.type||"submit"==t.type?"button":"input"};function d(t,e,n){let{currentContext:o,shortcuts:r}=e,{inAPI:i}=t,s={ev:t.ev,mainDependencies:t,regex:/FORM\s*\:/i,_defaults:h},c={currentContext:o,shortcuts:r,callbacks:{},typeFn:"",watchList:[],wait:{}};i._normalizeWithPlugins(f);let u=function(t,e){const{ev:n}=t;let o=null;function r(t,e,n,o){return{target:n.target,context:e.currentContext.name,note:e.currentContext.note,event:n,dependencies:t.mainDependencies.extra,type:o}}function i(o){const{callbacks:i,typeFn:s}=e,c=s(o.target),u=r(t,e,o,c),a=`${c}/in`;null!=i[a]&&n.emit(a,u,i[a])}function s(o){const{callbacks:i,typeFn:s}=e,c=r(t,e,o,"form-out"),u=`${s(o.target)}/out`;null!=i[u]&&n.emit(u,c,i[u])}function c(i){const{callbacks:s,typeFn:c}=e,u=r(t,e,i,"form-instant"),a=c(i.target),l=e.wait[`${a}`],m=`${a}/instant`;null!=s[m]&&(0!==l?(clearTimeout(o),o=setTimeout(()=>n.emit(m,u,s[m]),l)):n.emit(m,u,s[m]))}return{start:function(){e.active||(document.addEventListener("focusin",i),document.addEventListener("focusout",s),document.addEventListener("input",c),e.active=!0)},stop:function(){e.active&&(document.removeEventListener("focusin",i),document.removeEventListener("focusout",s),document.removeEventListener("input",c),e.active=!1)}}}(s,c);if(o.name){p(s,c)&&u.start()}let a={getPrefix:()=>"form",shortcutName:t=>f(t),contextChange:()=>{c.callbacks={},c.typeFn="",c.watchList=[],c.wait={},p(s,c)?u.start():u.stop()},mute:()=>u.stop(),unmute:()=>u.start(),destroy:()=>{u.stop()}};return Object.freeze(a),a}function g(n={}){let o={},r={};const i=t(),s={currentContext:{name:null,note:null},shortcuts:{},plugins:[],exposeShortcut:!(!n.onShortcut||"function"!=typeof n.onShortcut)&&n.onShortcut};let c={ev:i,inAPI:o,API:r,extra:{}};return r.enablePlugin=(t,e={})=>{const n=t.name.replace("plugin","").toLowerCase();if(-1===o._systemAction(n,"none")){let n=t(c,s,e);s.plugins.push(n)}},r.disablePlugin=t=>{const e=o._systemAction(t,"destroy");-1!==e&&(s.plugins=s.plugins.filter((t,n)=>n!==e))},r.mutePlugin=t=>o._systemAction(t,"mute"),r.unmutePlugin=t=>o._systemAction(t,"unmute"),r.getContext=()=>s.currentContext.name,r.getNote=()=>s.currentContext.note,r.setNote=(t=null)=>{"string"!=typeof t&&null!=t||(s.currentContext.note=t)},r.pause=(t="*")=>{let e=o._readShortcutWithPlugins(t);i.stop(e)},r.resume=(t="*")=>{const e=o._readShortcutWithPlugins(t);i.start(e)},r.emit=(t,...e)=>i.emit(o._readShortcutWithPlugins(t),...e),r.listContexts=()=>Object.keys(s.shortcuts),r.setDependencies=t=>c.extra={...c.extra,...t},r.getDependencies=()=>c.extra,r.reset=function(){i.reset(),r.changeContext(),s.plugins.forEach(t=>t.destroy()),r.listContexts().map(t=>r.unload(t)),c.extra={},s.exposeShortcut=null},Object.entries(e).forEach(([t,e])=>{t.startsWith("_")?o[t]=e(c,s):r[t]=e(c,s)}),r}export{m as pluginClick,d as pluginForm,s as pluginKey,g as shortcuts};
@@ -1 +1 @@
1
- !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).shortcuts={})}(this,function(t){"use strict";var e={_normalizeWithPlugins:function(t,e){return function(t){const n=e.shortcuts;Object.keys(n).forEach(e=>{Object.entries(n[e]).forEach(([o,r])=>{const i=t(o);i!==o&&(delete n[e][o],n[e][i]=r)})})}},_readShortcutWithPlugins:function(t,e){return function(n){const{inAPI:o}=t,r=n.split(":")[0],i=o._systemAction(r,"none");let s=n;return-1!==i&&(s=e.plugins[i].shortcutName(n)),s}},_systemAction:function(t,e){return function(t,n,o=null){return e.plugins.findIndex(e=>e.getPrefix()===t&&(e[n]&&e[n](o),!0))}},changeContext:function(t,e){const{shortcuts:n,currentContext:o}=e,{ev:r}=t;return function(t=!1){const i=o.name;if(!t)return r.reset(),void(o.name=null);i!==t&&(n[t]?(n[i]&&r.reset(),o.name=t,e.plugins.forEach(e=>e.contextChange(t)),Object.entries(n[t]).forEach(([t,e])=>{e.forEach(e=>r.on(t,e))}),r.on("*",(...t)=>{e.exposeShortcut&&e.exposeShortcut(...t)})):r.emit("@shortcuts-error",`Context '${t}' does not exist`))}},listShortcuts:function(t,e){const n=e.shortcuts;return function(t=null){if(null!=t){let e=n[t];return null==e?null:Object.entries(e).map(([t,e])=>t)}return Object.keys(n).map(t=>{let e={};return e.context=t,e.shortcuts=Object.entries(n[t]).map(([t,e])=>t),e})}},load:function(t,e){const{shortcuts:n,plugins:o}=e,{API:{changeContext:r,getContext:i}}=t;return function(t){const e=i(),s=o.map(t=>t.getPrefix().toUpperCase());let c=!1;Object.entries(t).forEach(([t,r])=>{t===e&&(c=!0),n[t]={},Object.entries(r).forEach(([e,r])=>{let i=e,c=e.toUpperCase().trim(),u=s.map((t,e)=>c.startsWith(t)?e:null).filter(t=>null!==t);if(u.length){let t=u[0];i=o[t].shortcutName(e)}r instanceof Function&&(r=[r]),n[t][i]=r})}),c&&(r(),r(e))}},unload:function(t,e){const{currentContext:n,shortcuts:o}=e,{ev:r}=t;return function(t){n.name!==t?o[t]?delete o[t]:r.emit("shortcuts-error",`Context '${t}' does not exist`):r.emit("shortcuts-error",`Context '${t}' can't be removed during is current active context. Change the context first`)}}};function n(t){const e=t.toUpperCase(),n=/KEY\s*\:/i.test(e),o=e.indexOf(":");if(!n)return t;return`KEY:${e.slice(o+1).split(",").map(t=>t.trim()).map(t=>t.split("+").map(t=>t.trim()).sort().join("+")).join(",")}`}function o(t,e){let{shiftKey:n,altKey:o,ctrlKey:r}=t,i=e(),s=t.code.replace("Key","").replace("Digit",""),c=[];return r&&c.push("CTRL"),n&&c.push("SHIFT"),o&&c.push("ALT"),i.hasOwnProperty(s)?c.push(i[s].toUpperCase()):["ControlLeft","ControlRight","ShiftLeft","ShiftRight","AltLeft","AltRight","Meta"].includes(s)||c.push(s.toUpperCase()),c.sort()}function r(t,e){let n=0;const{regex:o}=t,{listenOptions:r,currentContext:{name:i},shortcuts:s}=e;return null==i?0:(Object.entries(s[i]).forEach(([t,e])=>{if(!o.test(t))return;n++;let i=t.slice(4).split(",").length;r.maxSequence<i&&(r.maxSequence=i)}),n)}function i(){return{ArrowLeft:"LEFT",ArrowUp:"UP",ArrowRight:"RIGHT",ArrowDown:"DOWN",Enter:"ENTER",NumpadEnter:"ENTER",Escape:"ESC",Backspace:"BACKSPACE",Space:"SPACE",Tab:"TAB",Backquote:"`",BracketLeft:"[",BracketRight:"]",Equal:"=",Slash:"/",Backslash:"\\",IntlBackslash:"`",F1:"F1",F2:"F2",F3:"F3",F4:"F4",F5:"F5",F6:"F6",F7:"F7",F8:"F8",F9:"F9",F10:"F10",F11:"F11",F12:"F12"}}function s(t,e,n){const{listenOptions:{clickTarget:o}}=e;let r=n;return r===document||r===document.body?null:r.dataset[o]||"A"===r.nodeName?r:s(t,e,r.parentNode)}function c(t){const e=t.toUpperCase(),n=/CLICK\s*\:/i.test(e),o=["LEFT","MIDDLE","RIGHT"],r=["ALT","SHIFT","CTRL"];let i=null,s=[],c=0,u=e.indexOf(":");return n?(e.slice(u+1).trim().split("-").map(t=>t.trim()).forEach(t=>{o.includes(t)?i=t:r.includes(t)?s.push(t):isNaN(t)||(c=t)}),`CLICK:${i}-${c}${s.length>0?"-":""}${s.sort().join("-")}`):t}function u(t,e){let{shiftKey:n,altKey:o,ctrlKey:r,key:i,button:s}=t,c=`CLICK:${["LEFT","MIDDLE","RIGHT"][s]}-${e}`,u=[];return r&&u.push("CTRL"),n&&u.push("SHIFT"),o&&u.push("ALT"),u.length>0?`${c}${u.length>0?"-":""}${u.sort().join("-")}`:`${c}`}function l(t,e){let n=0;const{regex:o}=t,{listenOptions:r,currentContext:{name:i},shortcuts:s}=e;return null==i?0:(Object.entries(s[i]).forEach(([t,e])=>{if(!o.test(t))return;n++;let[,i]=t.slice(6).split("-");r.maxClicks<i&&(r.maxClicks=i)}),n)}function a(t){const e=t.toUpperCase(),n=/FORM\s*\:/i.test(e),o=e.indexOf(":");if(!n)return t;return`FORM:${e.slice(o+1).trim()}`}function f(t,e){const{regex:n,_defaults:o,ev:r}=t,{currentContext:{name:i},shortcuts:s,callbacks:c}=e;let u=[],l=[],a=[];if(null==i)return!1;if(Object.entries(s[i]).forEach(([t,e])=>{n.test(t)&&("FORM:WATCH"===t&&(u=e),"FORM:DEFINE"===t&&(l=e),"FORM:ACTION"===t&&(a=e))}),0===a.length)return!1;let f=new Set;0===l.length&&(l=[o.define]),0===u.length&&(u=[o.watch]);let m=u.map(t=>t()).reduce((t,e)=>(t.push(e),t),[]);return e.watchList=document.querySelectorAll(m),e.watchList.forEach(t=>f.add(l[0](t))),e.typeFn=l[0]?l[0]:o.define,a.forEach(t=>{if(!(t instanceof Function))return console.warn("Warning: The 'form:action' should be a function."),!1;if(!(t()instanceof Array))return console.warn("Warning: The 'form:action' function should RETURN an array."),!1;t().forEach(({fn:t,type:n,timing:o,wait:i=0})=>{if(f.has(n)&&t instanceof Function){let e=`${n}/${o}`;const i=c.hasOwnProperty(e);i?c[e].push(t):c[e]=[t],i||r.on(e,(t,e)=>{e.forEach(e=>{e instanceof Function&&e(t)})})}"instant"===o&&(e.wait[`${n}`]=i)})}),Object.keys(e.callbacks).length>0}const m={watch:()=>"input, select, textarea, button, a",define:t=>"checkbox"===t.type||"radio"===t.type?"checkbox":"button"==t.type||"submit"==t.type?"button":"input"};t.pluginClick=function(t,e,n){let{currentContext:o,shortcuts:r}=e,{inAPI:i}=t,a={ev:t.ev,_findTarget:s,_readClickEvent:u,mainDependencies:t,regex:/CLICK\s*\:/i},f={currentContext:o,shortcuts:r,listenOptions:{mouseWait:n.mouseWait?n.mouseWait:320,maxClicks:1,clickTarget:n.clickTarget?n.clickTarget:"click"}};i._normalizeWithPlugins(c);let m=function(t,e){const{ev:n,_findTarget:o,_readClickEvent:r,mainDependencies:i}=t,{listenOptions:s,currentContext:c}=e,{mouseWait:u}=s;let l=null,a=null,f=null,m=null,p=0;function h(){const t=r(a,p),e={target:l,targetProps:l?l.getBoundingClientRect():null,x:a.clientX,y:a.clientY,context:c.name,note:c.note,event:a,dependencies:i.extra,type:"click"};n.emit(t,e),f=null,m=null,l=null,a=null,p=0}function d(n){let r=s.maxClicks;return clearTimeout(f),m?(clearTimeout(m),void(m=setTimeout(()=>m=null,u))):(l=o(t,e,n.target),l&&l.dataset.hasOwnProperty("quickClick")&&(r=1),l&&"A"===l.tagName&&(r=1),a=n,p++,p>=r?(h(),void(r>1&&(m=setTimeout(()=>m=null,u)))):void(f=setTimeout(h,u)))}function g(n){let r=s.maxClicks;return clearTimeout(f),m?(clearTimeout(m),void(m=setTimeout(()=>m=null,u))):(l=o(t,e,n.target),l&&l.dataset.hasOwnProperty("quickClick")&&(r=1),l&&"A"===l.tagName&&(r=1),a=n,p++,p>=r?(h(),void(r>1&&(m=setTimeout(()=>m=null,u)))):void(f=setTimeout(h,u)))}return{start:function(){e.active||(window.addEventListener("contextmenu",g),document.addEventListener("click",d),e.active=!0)},stop:function(){e.active&&(window.removeEventListener("contextmenu",g),document.removeEventListener("click",d),e.active=!1)}}}(a,f),p=l(a,f);p>0&&m.start();let h={getPrefix:()=>"click",shortcutName:t=>c(t),contextChange:()=>{p=l(a,f),p<1&&m.stop(),p>0&&m.start()},mute:()=>m.stop(),unmute:()=>m.start(),destroy:()=>{m.stop(),f=null,h=null}};return Object.freeze(h),h},t.pluginForm=function(t,e,n){let{currentContext:o,shortcuts:r}=e,{inAPI:i}=t,s={ev:t.ev,mainDependencies:t,regex:/FORM\s*\:/i,_defaults:m},c={currentContext:o,shortcuts:r,callbacks:{},typeFn:"",watchList:[],wait:{}};i._normalizeWithPlugins(a);let u=function(t,e){const{ev:n}=t;let o=null;function r(t,e,n,o){return{target:n.target,context:e.currentContext.name,note:e.currentContext.note,event:n,dependencies:t.mainDependencies.extra,type:o}}function i(o){const{callbacks:i,typeFn:s}=e,c=s(o.target),u=r(t,e,o,c),l=`${c}/in`;null!=i[l]&&n.emit(l,u,i[l])}function s(o){const{callbacks:i,typeFn:s}=e,c=r(t,e,o,"form-out"),u=`${s(o.target)}/out`;null!=i[u]&&n.emit(u,c,i[u])}function c(i){const{callbacks:s,typeFn:c}=e,u=r(t,e,i,"form-instant"),l=c(i.target),a=e.wait[`${l}`],f=`${l}/instant`;null!=s[f]&&(0!==a?(clearTimeout(o),o=setTimeout(()=>n.emit(f,u,s[f]),a)):n.emit(f,u,s[f]))}return{start:function(){e.active||(document.addEventListener("focusin",i),document.addEventListener("focusout",s),document.addEventListener("input",c),e.active=!0)},stop:function(){e.active&&(document.removeEventListener("focusin",i),document.removeEventListener("focusout",s),document.removeEventListener("input",c),e.active=!1)}}}(s,c);if(o.name){f(s,c)&&u.start()}let l={getPrefix:()=>"form",shortcutName:t=>a(t),contextChange:()=>{c.callbacks={},c.typeFn="",c.watchList=[],c.wait={},f(s,c)?u.start():u.stop()},mute:()=>u.stop(),unmute:()=>u.start(),destroy:()=>{u.stop(),c=null,l=null}};return Object.freeze(l),l},t.pluginKey=function(t,e,s={}){let{currentContext:c,shortcuts:u,exposeShortcut:l}=e,{inAPI:a}=t,f={ev:t.ev,_specialChars:i,_readKeyEvent:o,mainDependencies:t,regex:/KEY\s*\:/i},m={currentContext:c,shortcuts:u,active:!1,listenOptions:{keyWait:s.keyWait?s.keyWait:480,maxSequence:1,keyIgnore:null},streamKeys:!(!s.streamKeys||"function"!=typeof s.streamKeys)&&s.streamKeys};a._normalizeWithPlugins(n);let p=function(t,e){const{ev:n,_specialChars:o,_readKeyEvent:r,mainDependencies:i}=t,{currentContext:s,streamKeys:c,listenOptions:u}=e,{keyWait:l}=u;let a=[],f=null,m=!0,p=!1;const h=()=>m=!1,d=()=>m=!0,g=()=>p=!0,y=()=>!1===m;function x(){let t=a.map(t=>[t.join("+")]);const e={wait:h,end:d,ignore:g,isWaiting:y,note:s.note,context:s.name,dependencies:i.extra,type:"key"};if(!m){let o=t.at(-1);n.emit(o,e),p&&(t=t.slice(0,-1),p=!1)}if(m){const o=`KEY:${t.join(",")}`;n.emit(o,e),a=[],f=null}}function v(e){if(clearTimeout(f),o().hasOwnProperty(e.code))return a.push(r(e,o)),c&&c({key:e.key,context:s.name,note:s.note,dependencies:t.extra}),u.keyIgnore?(clearTimeout(u.keyIgnore),void(u.keyIgnore=setTimeout(()=>u.keyIgnore=null,l))):m&&a.length===u.maxSequence?(x(),void(u.keyIgnore=setTimeout(()=>u.keyIgnore=null,l))):void(m?f=setTimeout(x,l):x())}function C(e){if(!o().hasOwnProperty(e.code)){if(clearTimeout(f),c&&c({key:e.key,context:s.name,note:s.note,dependencies:t.extra}),u.keyIgnore)return clearTimeout(u.keyIgnore),void(u.keyIgnore=setTimeout(()=>u.keyIgnore=null,l));if(a.push(r(e,o)),m&&a.length===u.maxSequence)return x(),void(u.keyIgnore=setTimeout(()=>u.keyIgnore=null,l));m?f=setTimeout(x,l):x()}}return{start:function(){e.active||(document.addEventListener("keydown",v),document.addEventListener("keypress",C),e.active=!0)},stop:function(){e.active&&(document.removeEventListener("keydown",v),document.removeEventListener("keypress",C),e.active=!1)}}}(f,m),h=r(f,m);h>0&&p.start();let d={getPrefix:()=>"key",shortcutName:t=>n(t),contextChange:t=>{h=r(f,m),h<1&&p.stop(),h>0&&p.start()},mute:()=>p.stop(),unmute:()=>p.start(),destroy:()=>{p.stop(),m=null,d=null}};return Object.freeze(d),d},t.shortcuts=function(t={}){const n=function(){let t={"*":[]},e={},n=new Set,o=!1,r="";return{on:function(e,n){t[e]||(t[e]=[]),t[e].push(n)},once:function(t,n){"*"!==t&&(e[t]||(e[t]=[]),e[t].push(n))},off:function(n,o){if(o)return t[n]&&(t[n]=t[n].filter(t=>t!==o)),e[n]&&(e[n]=e[n].filter(t=>t!==o)),t[n]&&0===t[n].length&&delete t[n],void(e[n]&&0===e[n].length&&delete t[n]);e[n]&&delete e[n],t[n]&&delete t[n]},reset:function(){t={"*":[]},e={},n=new Set},emit:function(){const[i,...s]=arguments;function c(e){let o=!1;"*"!==e&&(n.has(e)||(t[e].every(t=>{const e=t(...s);return"string"!=typeof e||"STOP"!==e.toUpperCase()||(o=!0,!1)}),o||t["*"].forEach(t=>t(i,...s))))}if(o&&(console.log(`${r} Event "${i}" was triggered.`),s.length>0&&(console.log("Arguments:"),console.log(...s),console.log("^----"))),"*"!==i){if(e[i]){if(n.has(i))return;e[i].forEach(t=>t(...s)),delete e[i]}t[i]&&c(i)}else Object.keys(t).forEach(t=>c(t))},stop:function(o){if("*"===o){const o=Object.keys(t),r=Object.keys(e);return void(n=new Set([...r,...o]))}n.add(o)},start:function(t){"*"!==t?n.delete(t):n.clear()},debug:function(t,e){o=!!t,e&&"string"==typeof e&&(r=e)}}}(),o={},r={},i={currentContext:{name:null,note:null},shortcuts:{},plugins:[],exposeShortcut:!(!t.onShortcut||"function"!=typeof t.onShortcut)&&t.onShortcut},s={ev:n,inAPI:o,API:r,extra:{}};return r.enablePlugin=(t,e={})=>{const n=t.name;if(-1===o._systemAction(n,"none")){let n;n=t(s,i,e),i.plugins.push(n)}},r.disablePlugin=t=>{const e=o._systemAction(t,"destroy");-1!==e&&(i.plugins=i.plugins.filter((t,n)=>n!==e))},r.mutePlugin=t=>o._systemAction(t,"mute"),r.unmutePlugin=t=>o._systemAction(t,"unmute"),r.getContext=()=>i.currentContext.name,r.getNote=()=>i.currentContext.note,r.setNote=(t=null)=>{"string"!=typeof t&&null!=t||(i.currentContext.note=t)},r.pause=(t="*")=>{let e=o._readShortcutWithPlugins(t);n.stop(e)},r.resume=(t="*")=>{const e=o._readShortcutWithPlugins(t);n.start(e)},r.emit=(t,...e)=>n.emit(o._readShortcutWithPlugins(t),...e),r.listContexts=()=>Object.keys(i.shortcuts),r.setDependencies=t=>s.extra={...s.extra,...t},r.getDependencies=()=>s.extra,Object.entries(e).forEach(([t,e])=>{t.startsWith("_")?o[t]=e(s,i):r[t]=e(s,i)}),r}});
1
+ !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).shortcuts={})}(this,function(t){"use strict";var e={_normalizeWithPlugins:function(t,e){return function(t){const n=e.shortcuts;Object.keys(n).forEach(e=>{Object.entries(n[e]).forEach(([o,r])=>{const i=t(o);i!==o&&(delete n[e][o],n[e][i]=r)})})}},_readShortcutWithPlugins:function(t,e){return function(n){const{inAPI:o}=t,r=n.split(":")[0].toLowerCase().trim(),i=o._systemAction(r,"none");let s=n;return-1!==i&&(s=e.plugins[i].shortcutName(n)),s}},_systemAction:function(t,e){return function(t,n,o=null){return e.plugins.findIndex(e=>e.getPrefix()===t&&(e[n]&&e[n](o),!0))}},changeContext:function(t,e){const{shortcuts:n,currentContext:o}=e,{ev:r}=t;return function(t=!1){const i=o.name;if(!t)return r.reset(),void(o.name=null);i!==t&&(n[t]?(n[i]&&r.reset(),o.name=t,e.plugins.forEach(e=>e.contextChange(t)),Object.entries(n[t]).forEach(([t,e])=>{e.forEach(e=>r.on(t,e))}),r.on("*",(...t)=>{e.exposeShortcut&&e.exposeShortcut(...t)})):r.emit("@shortcuts-error",`Context '${t}' does not exist`))}},listShortcuts:function(t,e){const n=e.shortcuts;return function(t=null){if(null!=t){let e=n[t];return null==e?null:Object.entries(e).map(([t,e])=>t)}return Object.keys(n).map(t=>{let e={};return e.context=t,e.shortcuts=Object.entries(n[t]).map(([t,e])=>t),e})}},load:function(t,e){const{shortcuts:n,plugins:o}=e,{API:{changeContext:r,getContext:i}}=t;return function(t){const e=i(),s=o.map(t=>t.getPrefix().toUpperCase());let c=!1;Object.entries(t).forEach(([t,r])=>{t===e&&(c=!0),n[t]={},Object.entries(r).forEach(([e,r])=>{let i=e,c=e.toUpperCase().trim(),u=s.map((t,e)=>c.startsWith(t)?e:null).filter(t=>null!==t);if(u.length){let t=u[0];i=o[t].shortcutName(e)}r instanceof Function&&(r=[r]),n[t][i]=r})}),c&&(r(),r(e))}},unload:function(t,e){const{currentContext:n,shortcuts:o}=e,{ev:r}=t;return function(t){n.name!==t?o[t]?delete o[t]:r.emit("shortcuts-error",`Context '${t}' does not exist`):r.emit("shortcuts-error",`Context '${t}' can't be removed during is current active context. Change the context first`)}}};function n(t){const e=t.toUpperCase(),n=/KEY\s*\:/i.test(e),o=e.indexOf(":");if(!n)return t;return`KEY:${e.slice(o+1).split(",").map(t=>t.trim()).map(t=>t.split("+").map(t=>t.trim()).sort().join("+")).join(",")}`}function o(t,e){let{shiftKey:n,altKey:o,ctrlKey:r}=t,i=e(),s=t.code.replace("Key","").replace("Digit",""),c=[];return r&&c.push("CTRL"),n&&c.push("SHIFT"),o&&c.push("ALT"),i.hasOwnProperty(s)?c.push(i[s].toUpperCase()):["ControlLeft","ControlRight","ShiftLeft","ShiftRight","AltLeft","AltRight","Meta"].includes(s)||c.push(s.toUpperCase()),c.sort()}function r(t,e){let n=0;const{regex:o}=t,{listenOptions:r,currentContext:{name:i},shortcuts:s}=e;return null==i?0:(Object.entries(s[i]).forEach(([t,e])=>{if(!o.test(t))return;n++;let i=t.slice(4).split(",").length;r.maxSequence<i&&(r.maxSequence=i)}),n)}function i(){return{ArrowLeft:"LEFT",ArrowUp:"UP",ArrowRight:"RIGHT",ArrowDown:"DOWN",Enter:"ENTER",NumpadEnter:"ENTER",Escape:"ESC",Backspace:"BACKSPACE",Space:"SPACE",Tab:"TAB",Backquote:"`",BracketLeft:"[",BracketRight:"]",Equal:"=",Slash:"/",Backslash:"\\",IntlBackslash:"`",F1:"F1",F2:"F2",F3:"F3",F4:"F4",F5:"F5",F6:"F6",F7:"F7",F8:"F8",F9:"F9",F10:"F10",F11:"F11",F12:"F12"}}function s(t,e,n){const{listenOptions:{clickTarget:o}}=e;let r=n;return r===document||r===document.body?null:r.dataset[o]||"A"===r.nodeName?r:s(t,e,r.parentNode)}function c(t){const e=t.toUpperCase(),n=/CLICK\s*\:/i.test(e),o=["LEFT","MIDDLE","RIGHT"],r=["ALT","SHIFT","CTRL"];let i=null,s=[],c=0,u=e.indexOf(":");return n?(e.slice(u+1).trim().split("-").map(t=>t.trim()).forEach(t=>{o.includes(t)?i=t:r.includes(t)?s.push(t):isNaN(t)||(c=t)}),`CLICK:${i}-${c}${s.length>0?"-":""}${s.sort().join("-")}`):t}function u(t,e){let{shiftKey:n,altKey:o,ctrlKey:r,key:i,button:s}=t,c=`CLICK:${["LEFT","MIDDLE","RIGHT"][s]}-${e}`,u=[];return r&&u.push("CTRL"),n&&u.push("SHIFT"),o&&u.push("ALT"),u.length>0?`${c}${u.length>0?"-":""}${u.sort().join("-")}`:`${c}`}function l(t,e){let n=0;const{regex:o}=t,{listenOptions:r,currentContext:{name:i},shortcuts:s}=e;return null==i?0:(Object.entries(s[i]).forEach(([t,e])=>{if(!o.test(t))return;n++;let[,i]=t.slice(6).split("-");r.maxClicks<i&&(r.maxClicks=i)}),n)}function a(t){const e=t.toUpperCase(),n=/FORM\s*\:/i.test(e),o=e.indexOf(":");if(!n)return t;return`FORM:${e.slice(o+1).trim()}`}function f(t,e){const{regex:n,_defaults:o,ev:r}=t,{currentContext:{name:i},shortcuts:s,callbacks:c}=e;let u=[],l=[],a=[];if(null==i)return!1;if(Object.entries(s[i]).forEach(([t,e])=>{n.test(t)&&("FORM:WATCH"===t&&(u=e),"FORM:DEFINE"===t&&(l=e),"FORM:ACTION"===t&&(a=e))}),0===a.length)return!1;let f=new Set;0===l.length&&(l=[o.define]),0===u.length&&(u=[o.watch]);let m=u.map(t=>t()).reduce((t,e)=>(t.push(e),t),[]);return e.watchList=document.querySelectorAll(m),e.watchList.forEach(t=>f.add(l[0](t))),e.typeFn=l[0]?l[0]:o.define,a.forEach(t=>{if(!(t instanceof Function))return console.warn("Warning: The 'form:action' should be a function."),!1;if(!(t()instanceof Array))return console.warn("Warning: The 'form:action' function should RETURN an array."),!1;t().forEach(({fn:t,type:n,timing:o,wait:i=0})=>{if(f.has(n)&&t instanceof Function){let e=`${n}/${o}`;const i=c.hasOwnProperty(e);i?c[e].push(t):c[e]=[t],i||r.on(e,(t,e)=>{e.forEach(e=>{e instanceof Function&&e(t)})})}"instant"===o&&(e.wait[`${n}`]=i)})}),Object.keys(e.callbacks).length>0}const m={watch:()=>"input, select, textarea, button, a",define:t=>"checkbox"===t.type||"radio"===t.type?"checkbox":"button"==t.type||"submit"==t.type?"button":"input"};t.pluginClick=function(t,e,n){let{currentContext:o,shortcuts:r}=e,{inAPI:i}=t,a={ev:t.ev,_findTarget:s,_readClickEvent:u,mainDependencies:t,regex:/CLICK\s*\:/i},f={currentContext:o,active:!1,shortcuts:r,listenOptions:{mouseWait:n.mouseWait?n.mouseWait:320,maxClicks:1,clickTarget:n.clickTarget?n.clickTarget:"click"}};i._normalizeWithPlugins(c);let m=function(t,e){const{ev:n,_findTarget:o,_readClickEvent:r,mainDependencies:i}=t,{listenOptions:s,currentContext:c}=e,{mouseWait:u}=s;let l=null,a=null,f=null,m=null,p=0;function h(){const t=r(a,p),e={target:l,targetProps:l?l.getBoundingClientRect():null,x:a.clientX,y:a.clientY,context:c.name,note:c.note,event:a,dependencies:i.extra,type:"click"};n.emit(t,e),f=null,m=null,l=null,a=null,p=0}function d(n){let r=s.maxClicks;return clearTimeout(f),m?(clearTimeout(m),void(m=setTimeout(()=>m=null,u))):(l=o(t,e,n.target),l&&l.dataset.hasOwnProperty("quickClick")&&(r=1),l&&"A"===l.tagName&&(r=1),a=n,p++,p>=r?(h(),void(r>1&&(m=setTimeout(()=>m=null,u)))):void(f=setTimeout(h,u)))}function g(n){let r=s.maxClicks;return clearTimeout(f),m?(clearTimeout(m),void(m=setTimeout(()=>m=null,u))):(l=o(t,e,n.target),l&&l.dataset.hasOwnProperty("quickClick")&&(r=1),l&&"A"===l.tagName&&(r=1),a=n,p++,p>=r?(h(),void(r>1&&(m=setTimeout(()=>m=null,u)))):void(f=setTimeout(h,u)))}return{start:function(){e.active||(window.addEventListener("contextmenu",g),document.addEventListener("click",d),e.active=!0)},stop:function(){e.active&&(window.removeEventListener("contextmenu",g),document.removeEventListener("click",d),e.active=!1,f&&(clearTimeout(f),f=null),m&&(clearTimeout(m),m=null),p=0)}}}(a,f),p=l(a,f);p>0&&m.start();let h={getPrefix:()=>"click",shortcutName:t=>c(t),contextChange:()=>{p=l(a,f),p<1&&m.stop(),p>0&&m.start()},mute:()=>{m.stop()},unmute:()=>m.start(),destroy:()=>m.stop()};return Object.freeze(h),h},t.pluginForm=function(t,e,n){let{currentContext:o,shortcuts:r}=e,{inAPI:i}=t,s={ev:t.ev,mainDependencies:t,regex:/FORM\s*\:/i,_defaults:m},c={currentContext:o,shortcuts:r,callbacks:{},typeFn:"",watchList:[],wait:{}};i._normalizeWithPlugins(a);let u=function(t,e){const{ev:n}=t;let o=null;function r(t,e,n,o){return{target:n.target,context:e.currentContext.name,note:e.currentContext.note,event:n,dependencies:t.mainDependencies.extra,type:o}}function i(o){const{callbacks:i,typeFn:s}=e,c=s(o.target),u=r(t,e,o,c),l=`${c}/in`;null!=i[l]&&n.emit(l,u,i[l])}function s(o){const{callbacks:i,typeFn:s}=e,c=r(t,e,o,"form-out"),u=`${s(o.target)}/out`;null!=i[u]&&n.emit(u,c,i[u])}function c(i){const{callbacks:s,typeFn:c}=e,u=r(t,e,i,"form-instant"),l=c(i.target),a=e.wait[`${l}`],f=`${l}/instant`;null!=s[f]&&(0!==a?(clearTimeout(o),o=setTimeout(()=>n.emit(f,u,s[f]),a)):n.emit(f,u,s[f]))}return{start:function(){e.active||(document.addEventListener("focusin",i),document.addEventListener("focusout",s),document.addEventListener("input",c),e.active=!0)},stop:function(){e.active&&(document.removeEventListener("focusin",i),document.removeEventListener("focusout",s),document.removeEventListener("input",c),e.active=!1)}}}(s,c);if(o.name){f(s,c)&&u.start()}let l={getPrefix:()=>"form",shortcutName:t=>a(t),contextChange:()=>{c.callbacks={},c.typeFn="",c.watchList=[],c.wait={},f(s,c)?u.start():u.stop()},mute:()=>u.stop(),unmute:()=>u.start(),destroy:()=>{u.stop()}};return Object.freeze(l),l},t.pluginKey=function(t,e,s={}){let{currentContext:c,shortcuts:u,exposeShortcut:l}=e,{inAPI:a}=t,f={ev:t.ev,_specialChars:i,_readKeyEvent:o,mainDependencies:t,regex:/KEY\s*\:/i},m={currentContext:c,shortcuts:u,active:!1,listenOptions:{keyWait:s.keyWait?s.keyWait:480,maxSequence:1,keyIgnore:null},streamKeys:!(!s.streamKeys||"function"!=typeof s.streamKeys)&&s.streamKeys};a._normalizeWithPlugins(n);let p=function(t,e){const{ev:n,_specialChars:o,_readKeyEvent:r,mainDependencies:i}=t,{currentContext:s,streamKeys:c,listenOptions:u}=e,{keyWait:l}=u;let a=[],f=null,m=!0,p=!1;const h=()=>m=!1,d=()=>m=!0,g=()=>p=!0,y=()=>!1===m;function x(){let t=a.map(t=>[t.join("+")]);const e={wait:h,end:d,ignore:g,isWaiting:y,note:s.note,context:s.name,dependencies:i.extra,type:"key"};if(!m){let o=t.at(-1);n.emit(o,e),p&&(t=t.slice(0,-1),p=!1)}if(m){const o=`KEY:${t.join(",")}`;n.emit(o,e),a=[],f=null}}function C(e){if(clearTimeout(f),o().hasOwnProperty(e.code))return a.push(r(e,o)),c&&c({key:e.key,context:s.name,note:s.note,dependencies:t.extra}),u.keyIgnore?(clearTimeout(u.keyIgnore),void(u.keyIgnore=setTimeout(()=>u.keyIgnore=null,l))):m&&a.length===u.maxSequence?(x(),void(u.keyIgnore=setTimeout(()=>u.keyIgnore=null,l))):void(m?f=setTimeout(x,l):x())}function k(e){if(!o().hasOwnProperty(e.code)){if(clearTimeout(f),c&&c({key:e.key,context:s.name,note:s.note,dependencies:t.extra}),u.keyIgnore)return clearTimeout(u.keyIgnore),void(u.keyIgnore=setTimeout(()=>u.keyIgnore=null,l));if(a.push(r(e,o)),m&&a.length===u.maxSequence)return x(),void(u.keyIgnore=setTimeout(()=>u.keyIgnore=null,l));m?f=setTimeout(x,l):x()}}return{start:function(){e.active||(document.addEventListener("keydown",C),document.addEventListener("keypress",k),e.active=!0)},stop:function(){e.active&&(document.removeEventListener("keydown",C),document.removeEventListener("keypress",k),e.active=!1,f&&(clearTimeout(f),f=null),u.keyIgnore&&(clearTimeout(u.keyIgnore),u.keyIgnore=null),a=[],m=!0,p=!1)}}}(f,m),h=r(f,m);h>0&&p.start();let d={getPrefix:()=>"key",shortcutName:t=>n(t),contextChange:t=>{h=r(f,m),h<1&&p.stop(),h>0&&p.start()},mute:()=>p.stop(),unmute:()=>p.start(),destroy:()=>p.stop()};return Object.freeze(d),d},t.shortcuts=function(t={}){let n={},o={};const r=function(){let t={"*":[]},e={},n=new Set,o=!1,r="";return{on:function(e,n){t[e]||(t[e]=[]),t[e].push(n)},once:function(t,n){"*"!==t&&(e[t]||(e[t]=[]),e[t].push(n))},off:function(n,o){if(o)return t[n]&&(t[n]=t[n].filter(t=>t!==o)),e[n]&&(e[n]=e[n].filter(t=>t!==o)),t[n]&&0===t[n].length&&delete t[n],void(e[n]&&0===e[n].length&&delete t[n]);e[n]&&delete e[n],t[n]&&delete t[n]},reset:function(){t={"*":[]},e={},n=new Set},emit:function(){const[i,...s]=arguments;function c(e){let o=!1;"*"!==e&&(n.has(e)||(t[e].every(t=>{const e=t(...s);return"string"!=typeof e||"STOP"!==e.toUpperCase()||(o=!0,!1)}),o||t["*"].forEach(t=>t(i,...s))))}if(o&&(console.log(`${r} Event "${i}" was triggered.`),s.length>0&&(console.log("Arguments:"),console.log(...s),console.log("^----"))),"*"!==i){if(e[i]){if(n.has(i))return;e[i].forEach(t=>t(...s)),delete e[i]}t[i]&&c(i)}else Object.keys(t).forEach(t=>c(t))},stop:function(o){if("*"===o){const o=Object.keys(t),r=Object.keys(e);return void(n=new Set([...r,...o]))}n.add(o)},start:function(t){"*"!==t?n.delete(t):n.clear()},debug:function(t,e){o=!!t,e&&"string"==typeof e&&(r=e)}}}(),i={currentContext:{name:null,note:null},shortcuts:{},plugins:[],exposeShortcut:!(!t.onShortcut||"function"!=typeof t.onShortcut)&&t.onShortcut};let s={ev:r,inAPI:n,API:o,extra:{}};return o.enablePlugin=(t,e={})=>{const o=t.name.replace("plugin","").toLowerCase();if(-1===n._systemAction(o,"none")){let n=t(s,i,e);i.plugins.push(n)}},o.disablePlugin=t=>{const e=n._systemAction(t,"destroy");-1!==e&&(i.plugins=i.plugins.filter((t,n)=>n!==e))},o.mutePlugin=t=>n._systemAction(t,"mute"),o.unmutePlugin=t=>n._systemAction(t,"unmute"),o.getContext=()=>i.currentContext.name,o.getNote=()=>i.currentContext.note,o.setNote=(t=null)=>{"string"!=typeof t&&null!=t||(i.currentContext.note=t)},o.pause=(t="*")=>{let e=n._readShortcutWithPlugins(t);r.stop(e)},o.resume=(t="*")=>{const e=n._readShortcutWithPlugins(t);r.start(e)},o.emit=(t,...e)=>r.emit(n._readShortcutWithPlugins(t),...e),o.listContexts=()=>Object.keys(i.shortcuts),o.setDependencies=t=>s.extra={...s.extra,...t},o.getDependencies=()=>s.extra,o.reset=function(){r.reset(),o.changeContext(),i.plugins.forEach(t=>t.destroy()),o.listContexts().map(t=>o.unload(t)),s.extra={},i.exposeShortcut=null},Object.entries(e).forEach(([t,e])=>{t.startsWith("_")?n[t]=e(s,i):o[t]=e(s,i)}),o}});
package/jsconfig.json ADDED
@@ -0,0 +1,10 @@
1
+ {
2
+ "compilerOptions": {
3
+ "checkJs": false, // Disables type checking in .js files
4
+ "noImplicitAny": false,
5
+ "strict": false,
6
+ "allowJs": true,
7
+ },
8
+ "include": ["src/**/*", "tests/**/*", "**/*.js"], // Your files
9
+
10
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@peter.naydenov/shortcuts",
3
3
  "description": "Context control of shortcuts based on keyboard and mouse events",
4
- "version": "3.3.1",
4
+ "version": "3.4.0",
5
5
  "license": "MIT",
6
6
  "author": "Peter Naydenov",
7
7
  "main": "./dist/shortcuts.umd.js",
@@ -19,7 +19,9 @@
19
19
  "scripts": {
20
20
  "dev": "vite",
21
21
  "build": "rollup -c",
22
- "test": "vitest --workspace=vitest.workspace.js"
22
+ "test": "vitest",
23
+ "test:ui": "vitest --ui",
24
+ "cover": "vitest run --coverage"
23
25
  },
24
26
  "repository": {
25
27
  "type": "git",
@@ -30,18 +32,22 @@
30
32
  },
31
33
  "devDependencies": {
32
34
  "@peter.naydenov/visual-controller-for-react": "^3.0.1",
33
- "@rollup/plugin-commonjs": "^28.0.6",
34
- "@rollup/plugin-node-resolve": "^16.0.2",
35
+ "@rollup/plugin-commonjs": "^28.0.8",
36
+ "@rollup/plugin-node-resolve": "^16.0.3",
35
37
  "@rollup/plugin-terser": "^0.4.4",
38
+ "@testing-library/dom": "^10.4.1",
36
39
  "@vitejs/plugin-react": "^5.0.4",
37
40
  "@vitest/browser": "^3.2.4",
41
+ "@vitest/coverage-v8": "^3.2.4",
42
+ "@vitest/ui": "^3.2.4",
38
43
  "ask-for-promise": "^3.0.2",
39
44
  "chai": "^6.2.0",
40
45
  "mocha": "^11.7.4",
41
- "playwright": "^1.56.0",
46
+ "playwright": "^1.56.1",
42
47
  "react": "^19.2.0",
43
48
  "react-dom": "^19.2.0",
44
- "vite": "^7.1.9"
49
+ "vite": "^7.1.10",
50
+ "vitest": "^3.2.4"
45
51
  },
46
52
  "keywords": [
47
53
  "shortcut",
package/src/main.js CHANGED
@@ -31,24 +31,25 @@ import pluginForm from './plugins/form/index.js'
31
31
 
32
32
 
33
33
  function main ( options = {} ) {
34
-
34
+ let
35
+ inAPI = {} // API for internal methods
36
+ , API = {} // API for public methods
37
+ ;
35
38
  const
36
39
  ev = notice () // Event emitter instance
37
- , inAPI = {} // API for internal methods
38
- , API = {} // API for public methods
39
40
  , state = {
40
41
  currentContext : { name: null, note: null } // Context data container
41
42
  , shortcuts : {} // shortcuts = { contextName : { shortcut : callback[] } }
42
43
  , plugins : [] // Array of active plugins
43
44
  , exposeShortcut : (options.onShortcut && ( typeof options.onShortcut === 'function')) ? options.onShortcut : false // Keyboard shortcut log function
44
45
  } // state
45
- , dependencies = {
46
+ ;
47
+ let dependencies = {
46
48
  ev
47
49
  , inAPI
48
50
  , API
49
51
  , extra : {}
50
- }
51
- ;
52
+ };
52
53
 
53
54
 
54
55
 
@@ -58,15 +59,15 @@ function main ( options = {} ) {
58
59
  * @description Enable a plugin
59
60
  * @returns {void}
60
61
  */
61
- API.enablePlugin = ( plugin,options={}) => {
62
+ API.enablePlugin = ( plugin, options={}) => {
62
63
  const
63
- name = plugin.name
64
+ name = plugin.name.replace ( 'plugin', '' ).toLowerCase ()
64
65
  , ix = inAPI._systemAction ( name, 'none' )
65
66
  ;
66
67
 
67
68
  if ( ix === -1 ) { // If plugin is not registered
68
- let plugApp; // Started instance of the plugin
69
- plugApp = plugin ( dependencies, state, options )
69
+ // Started instance of the plugin
70
+ let plugApp = plugin ( dependencies, state, options )
70
71
  state.plugins.push ( plugApp )
71
72
  }
72
73
  } // enable func.
@@ -181,6 +182,21 @@ function main ( options = {} ) {
181
182
  API.getDependencies = () => dependencies.extra
182
183
 
183
184
 
185
+ /**
186
+ * @function reset
187
+ * @description Reset the library instance
188
+ * @returns {void}
189
+ */
190
+ API.reset = function reset () {
191
+ ev.reset ()
192
+ API.changeContext ()
193
+ state.plugins.forEach ( plugin => plugin.destroy () )
194
+ API.listContexts ().map ( cx => API.unload ( cx ))
195
+ dependencies.extra = {}
196
+ state.exposeShortcut = null
197
+ } // reset func.
198
+
199
+
184
200
 
185
201
  Object.entries ( methods ).forEach ( ([ name, method ]) => {
186
202
  if ( name.startsWith('_') ) inAPI [ name ] = method ( dependencies, state )
@@ -9,9 +9,10 @@ function _readShortcutWithPlugins ( dependencies, state ) {
9
9
  return function _readShortcutWithPlugins ( shortcut ) {
10
10
  const
11
11
  { inAPI } = dependencies
12
- , pluginName = shortcut.split(':')[0]
12
+ , pluginName = shortcut.split(':')[0].toLowerCase().trim()
13
13
  , ix = inAPI._systemAction ( pluginName, 'none' ) // Find a index. Don't call any method.
14
14
  ;
15
+
15
16
  let pausedEvent = shortcut;
16
17
  if ( ix !== -1 ) pausedEvent = state.plugins[ix].shortcutName ( shortcut )
17
18
  return pausedEvent
@@ -10,7 +10,8 @@
10
10
  function listShortcuts ( dependencies, state ) {
11
11
  const shortcuts = state.shortcuts;
12
12
  /**
13
- * List all shortcuts in all contexts or in a specific context.
13
+ * @function listShortcuts
14
+ * @description List all shortcuts in all contexts or in a specific context.
14
15
  * @param {string}[ contextName=null] - List of shortcuts for provided context name. (optional)
15
16
  * @returns {string[]|contextShortcuts[]} - List of shortcuts for a specified context or list of contextShortcuts for all contexts.
16
17
  */
@@ -19,9 +19,11 @@ return function load ( shortcutsUpdate ) {
19
19
  let hasChanges = false;
20
20
 
21
21
  Object.entries ( shortcutsUpdate ).forEach ( ([contextName, contextShortcuts]) => {
22
- if ( contextName === currentContextName ) hasChanges = true; // If changes in current context will need to reload it
22
+ // If changes in current context will need to reload it
23
+ if ( contextName === currentContextName ) hasChanges = true;
23
24
  shortcuts [ contextName ] = {}
24
- Object.entries ( contextShortcuts ).forEach ( ([ title, callbackList ]) => {
25
+
26
+ Object.entries ( contextShortcuts ).forEach ( ([ title, payload ]) => {
25
27
  let
26
28
  name = title
27
29
  , test = title.toUpperCase().trim()
@@ -31,8 +33,8 @@ return function load ( shortcutsUpdate ) {
31
33
  let id = pluginIndexList[0];
32
34
  name = plugins[id].shortcutName ( title )
33
35
  }
34
- if ( callbackList instanceof Function ) callbackList = [ callbackList ]
35
- shortcuts [contextName][ name ] = callbackList
36
+ if ( payload instanceof Function ) payload = [ payload ]
37
+ shortcuts [contextName][ name ] = payload
36
38
  }) // contextShortcuts.forEach
37
39
  }) // shortcutsUpdate.forEach
38
40
  if ( hasChanges ) { // Reload context shortcuts after loading process if context was active
@@ -95,16 +95,26 @@ function _listenDOM ( dependencies, state ) {
95
95
 
96
96
  function start () {
97
97
  if ( state.active ) return
98
- window.addEventListener ( 'contextmenu', listenRightClick )
98
+ window.addEventListener ( 'contextmenu', listenRightClick )
99
99
  document.addEventListener ( 'click' , listenLeftClick )
100
100
  state.active = true
101
101
  } // start func.
102
102
 
103
103
  function stop () {
104
104
  if ( !state.active ) return
105
- window.removeEventListener ( 'contextmenu', listenRightClick )
105
+ window.removeEventListener ( 'contextmenu', listenRightClick )
106
106
  document.removeEventListener ( 'click' , listenLeftClick )
107
107
  state.active = false
108
+ // Clear any pending timers to prevent state pollution between tests
109
+ if ( mouseTimer ) {
110
+ clearTimeout ( mouseTimer )
111
+ mouseTimer = null
112
+ }
113
+ if ( mouseIgnore ) {
114
+ clearTimeout ( mouseIgnore )
115
+ mouseIgnore = null
116
+ }
117
+ count = 0
108
118
  } // stop func.
109
119
 
110
120
  return { start, stop }
@@ -22,6 +22,7 @@ function pluginClick ( dependencies, state, options ) {
22
22
  }
23
23
  , pluginState = {
24
24
  currentContext
25
+ , active : false
25
26
  , shortcuts
26
27
  , listenOptions : {
27
28
  mouseWait : options.mouseWait ? options.mouseWait : 320 // 320 ms
@@ -55,13 +56,12 @@ function pluginClick ( dependencies, state, options ) {
55
56
  mouseListener.start ()
56
57
  }
57
58
  }
58
- , mute : () => mouseListener.stop ()
59
+ , mute : () => {
60
+
61
+ mouseListener.stop ()
62
+ }
59
63
  , unmute : () => mouseListener.start ()
60
- , destroy : () => {
61
- mouseListener.stop ()
62
- pluginState = null
63
- pluginAPI = null
64
- }
64
+ , destroy : () => mouseListener.stop ()
65
65
  }; // pluginAPI
66
66
  Object.freeze ( pluginAPI )
67
67
  return pluginAPI
@@ -71,10 +71,10 @@ function pluginForm ( dependencies, state, options ) {
71
71
  , mute : () => formListener.stop ()
72
72
  , unmute : () => formListener.start ()
73
73
  , destroy : () => {
74
- formListener.stop ()
75
- pluginState = null
76
- pluginAPI = null
77
- }
74
+ formListener.stop ()
75
+ // TODO: Clean up state of the plugin
76
+ }
77
+
78
78
  }; // pluginAPI
79
79
  Object.freeze ( pluginAPI )
80
80
  return pluginAPI
@@ -126,6 +126,19 @@ function _listenDOM ( dependencies, state ) {
126
126
  document.removeEventListener ( 'keydown' , listenForSpecialKeys )
127
127
  document.removeEventListener ( 'keypress', listenForRegularKeys )
128
128
  state.active = false
129
+ // Clear any pending timers to prevent state pollution between tests
130
+ if ( keyTimer ) {
131
+ clearTimeout ( keyTimer )
132
+ keyTimer = null
133
+ }
134
+ if ( listenOptions.keyIgnore ) {
135
+ clearTimeout ( listenOptions.keyIgnore )
136
+ listenOptions.keyIgnore = null
137
+ }
138
+ // Reset all state variables to prevent interference between tests
139
+ r = []
140
+ sequence = true
141
+ ignore = false
129
142
  }
130
143
 
131
144
  return { start, stop }
@@ -59,11 +59,7 @@ function pluginKey ( dependencies, state, options={} ) {
59
59
  }
60
60
  , mute : () => keysListener.stop ()
61
61
  , unmute : () => keysListener.start ()
62
- , destroy : () => {
63
- keysListener.stop ()
64
- pluginState = null
65
- pluginAPI = null
66
- }
62
+ , destroy : () => keysListener.stop ()
67
63
  };
68
64
  Object.freeze ( pluginAPI )
69
65
  return pluginAPI