@peter.naydenov/cuts 1.4.5 → 1.6.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,84 +1,126 @@
1
1
  # Release History
2
2
 
3
3
 
4
- ## 1.4.5 ( 2025-10-20 )
4
+ ## 1.6.0 ( 2025-10-?? )
5
+ - [x] All 'cuts' errors goes to '@app-error' event;
6
+ - [x] Configuration 'logLevel' default value is 1. If you want to dissable errors logging, set 'logLevel' to 0;
7
+ - [x] Code cleaning. Removing unused code;
8
+ - [x] Test code coverage on 85%;
9
+ - [x] Fix: SSR option for first scene loading;
10
+
11
+
12
+
13
+
14
+ ## 1.5.0 ( 2025-10-23 )
5
15
  - [x] Dependency update. @peter.naydenov/shortcuts - v.3.5.1
16
+ - [x] Dev dependency update. Vitest - v.4.0.1
6
17
  - [x] Cuts has event '@app-error'. Shortcut errors will trigger this event;
7
18
  - [x] Type improvements;
19
+ - [x] New method `getState` returns an object with the current state;
20
+ - [x] Fix: Closing a long list of scenes breaks the state;
21
+ - [ ] Bug: SSR option for first scene loading;
8
22
 
9
23
 
10
24
 
11
25
  ## 1.4.4 ( 2025-10-10)
12
26
  - [x] Dependency update. @peter.naydenov/shortcuts - v.3.3.1 ( fixing problem with 'key:specialCharacters' events);
27
+ - [ ] Bug: Closing a long list of scenes breaks the state;
28
+ - [ ] Bug: SSR option for first scene loading;
13
29
 
14
30
 
15
31
 
16
32
  ## 1.4.3 ( 2025-09-30)
17
33
  - [x] Dependency update. ask-for-promise@3.0.2;
34
+ - [ ] Bug: Closing a long list of scenes breaks the state;
35
+ - [ ] Bug: SSR option for first scene loading;
18
36
 
19
37
 
20
38
 
21
39
  ## 1.4.2 ( 2025-09-29)
22
40
  - [x] Dependency update. @peter.naydenov/shortcuts@3.3.0;
41
+ - [ ] Bug: Closing a long list of scenes breaks the state;
42
+ - [ ] Bug: SSR option for first scene loading;
43
+
44
+
23
45
 
24
46
  ## 1.4.1. ( 2025-09-24)
25
47
  - [x] Fix: Cleaning a duplicated line of code in main.js;
26
-
48
+ - [ ] Bug: Closing a long list of scenes breaks the state;
49
+ - [ ] Bug: SSR option for first scene loading;
27
50
 
28
51
 
29
52
  ## 1.4.0 ( 2025-09-06)
30
53
  - [x] New methods: jump, jumpBack, jumpsReset;
31
54
  - [ ] Bug: Duplicated line of code in main.js;
55
+ - [ ] Bug: Closing a long list of scenes breaks the state;
56
+ - [ ] Bug: SSR option for first scene loading;
32
57
 
33
58
 
34
59
  ## 1.3.1 ( 2025-08-15)
35
60
  - [ ] Fix: Missing typedef for plugin 'form'
61
+ - [ ] Bug: Closing a long list of scenes breaks the state;
62
+ - [ ] Bug: SSR option for first scene loading;
36
63
 
37
64
 
38
65
  ## 1.3.0 ( 2025-08-15)
39
66
  - [x] Dependency update. @peter.naydenov/shortcuts@3.1.5. Plugin 'form' is available;
40
67
  - [ ] Miss: Missing typedef for plugin 'form'
41
-
68
+ - [ ] Bug: Closing a long list of scenes breaks the state;
69
+ - [ ] Bug: SSR option for first scene loading;
42
70
 
43
71
 
44
72
  ## 1.2.8 ( 2025-05-03)
45
73
  - [x] Dependency update. @peter.naydenov/shortcuts@3.1.4;
74
+ - [ ] Bug: Closing a long list of scenes breaks the state;
75
+ - [ ] Bug: SSR option for first scene loading;
76
+
46
77
 
47
78
 
48
79
  ### 1.2.7 ( 2025-02-04)
49
80
  - [x] Dependency update. @peter.naydenov/log@1.1.1;
81
+ - [ ] Bug: Closing a long list of scenes breaks the state;
82
+ - [ ] Bug: SSR option for first scene loading;
50
83
 
51
84
 
52
85
 
53
86
  ### 1.2.6 ( 2025-01-23)
54
87
  - [x] Improve: Warn that the scene is not defined if scene is set to null;
88
+ - [ ] Bug: Closing a long list of scenes breaks the state;
89
+ - [ ] Bug: SSR option for first scene loading;
55
90
 
56
91
 
57
92
 
58
93
  ### 1.2.4 ( 2025-01-15)
59
94
  - [x] Dependency update. @peter.naydenov/shortcuts@3.1.3;
95
+ - [ ] Bug: Closing a long list of scenes breaks the state;
96
+ - [ ] Bug: SSR option for first scene loading;
60
97
 
61
98
 
62
99
 
63
100
  ### 1.2.3 ( 2024-12-23)
64
101
  - [x] Dependency update. @peter.naydenov/shortcuts@3.1.2;
65
-
102
+ - [ ] Bug: Closing a long list of scenes breaks the state;
103
+ - [ ] Bug: SSR option for first scene loading;
66
104
 
67
105
 
68
106
  ### 1.2.2 ( 2024-12-22 )
69
107
  - [x] Fix: Wrong argument 'dependencies' for 'beforeHide' and 'afterShow' methods;
70
-
71
-
108
+ - [ ] Bug: Closing a long list of scenes breaks the state;
109
+ - [ ] Bug: SSR option for first scene loading;
72
110
 
73
111
  ### 1.2.1 ( 2024-12-21 )
74
112
  - [x] Fix: Wrong settings if missing 'beforeHide' method;
75
113
  - [ ] Bug: Wrong argument 'dependencies' for 'beforeHide' and 'afterShow' methods;
114
+ - [ ] Bug: Closing a long list of scenes breaks the state;
115
+ - [ ] Bug: SSR option for first scene loading;
76
116
 
77
117
 
78
118
  ### 1.2.0 (2024-12-21)
79
119
  - [x] Extend 'scene' with optional 'afterShow' and 'beforeHide' methods;
80
120
  - [ ] Bug: Wrong settings if missing 'beforeHide' method;
81
121
  - [ ] Bug: Wrong argument 'dependencies' for 'beforeHide' and 'afterShow' methods;
122
+ - [ ] Bug: Closing a long list of scenes breaks the state;
123
+ - [ ] Bug: SSR option for first scene loading;
82
124
 
83
125
 
84
126
 
@@ -86,16 +128,23 @@
86
128
  - [x] Type improvements;
87
129
  - [x] Refactoring related to types;
88
130
  - [x] New method `loadPlugins` to load shortcut plugins: `Key`, `Click` or both;
131
+ - [x] Method 'setScene' errors goes to '@app-error'
132
+ - [ ] Bug: Closing a long list of scenes breaks the state;
133
+ - [ ] Bug: SSR option for first scene loading;
89
134
 
90
135
 
91
136
 
92
137
  ### 1.0.2 (2024-12-12)
93
138
  - [x] Create d.ts files in folder 'types';
139
+ - [ ] Bug: Closing a long list of scenes breaks the state;
140
+ - [ ] Bug: SSR option for first scene loading;
94
141
 
95
142
 
96
143
 
97
144
  ### 1.0.1 (2024-05-10)
98
145
  - [x] Fix: Repository address in package.json;
146
+ - [ ] Bug: Closing a long list of scenes breaks the state;
147
+ - [ ] Bug: SSR option for first scene loading;
99
148
 
100
149
 
101
150
 
package/README.md CHANGED
@@ -55,6 +55,7 @@ script.show ({ scene : 'sceneName'}) // change the current Scene
55
55
  , getDependencies : 'Returns the "dependencies" object'
56
56
  , enablePlugin : 'Enable a shortcut plugin. Available after version 1.1.0'
57
57
  , disablePlugin : 'Disable a shortcut plugin. Available after version 1.1.0'
58
+ , getState : 'Get the current state of the application'
58
59
  , emit : 'Emit an event'
59
60
  ```
60
61
 
package/dist/cuts.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";var e=require("@peter.naydenov/shortcuts"),n=require("ask-for-promise"),r=require("@peter.naydenov/log");function*t(e,n,r,t){let s=null;if(null===e)return yield*t.map(e=>[e,"show"]),void(yield[r,"show"]);if(!t||0===t.length)return n?(yield[e,"hide"],n.reverse(),yield*n.map(e=>[e,"hide"]),void(yield[r,"show"])):(yield[e,"hide"],void(yield[r,"show"]));if(t.includes(e)){for(let n=t.indexOf(e)+1;n<t.length;n++)yield[t[n],"show"];return void(yield[r,"show"])}if(!n)return yield[e,"hide"],void(yield*t.map(e=>[e,"show"]));if(t.every((e,r)=>n[r]===t[r]&&(s=r,!0)),null==s)return yield[e,"hide"],n.reverse(),yield*n.map(e=>[e,"hide"]),yield*t.map(e=>[e,"show"]),void(yield[r,"show"]);yield[e,"hide"];for(let e=n.length;e>s+1;e--)yield[n[e-1],"hide"];for(let e=s+1;e<t.length;e++)yield[t[e],"show"];yield[r,"show"]}function s(e){return function(n,...r){const{askForPromise:t,deps:s}=e;return function(){const e=t();return n({task:e,dependencies:s()},...r),e.promise}}}module.exports=function(o={logLevel:0}){const c=e.shortcuts({errorEventName:"@app-error"}),i=o.logLevel||0,u=r({level:i}),d={currentScene:null,currentParents:null,sceneNames:new Set,scenes:{},opened:!1,jumpStack:[]},l={},a={shortcutMngr:c,findInstructions:t,askForPromise:n,setInstruction:s({askForPromise:n,deps:c.getDependencies}),log:u};return l.hide=function(e,n){return function(r=1){const{askForPromise:t,shortcutMngr:s,setInstruction:o}=e,{currentScene:c,currentParents:i,scenes:u}=n,d=t(),l=[],a=i.length>0;let p;return s.pause(),l.push(o(u[c].hide)),a||(n.currentScene=null),a&&"*"===r&&[...i].reverse().forEach(e=>{p=n.currentParents.pop(),n.currentScene=p,l.push(o(u[e].hide))}),a&&!["*",1].includes(r)&&i.slice("-"+(r-1)).reverse().map(e=>{p=n.currentParents.pop(),n.currentScene=p,l.push(o(u[e].hide))}),(r=t.sequence(l)).onComplete(()=>{s.changeContext(n.currentScene),d.done()}),d.promise}}(a,d),l.listShortcuts=function(e,n){return function(e){const{scenes:r,sceneNames:t}=n;if(!t.has(e))return null;const{show:s,hide:o,parents:c,beforeUnload:i,afterLoad:u,...d}=r[e];return Object.keys(d)}}(0,d),l.setScenes=function(e,n){return function(r){const{shortcutMngr:t}=e;r.forEach(e=>{if(null==e)return;const{name:r,scene:s}=e;if(null==s)return void console.warn(`Scene ${r} is not defined`);s.parents||(s.parents=[]),n.scenes[r]=s,n.sceneNames.add(r);const{show:o,hide:c,parents:i,...u}=s,d={};d[r]=u,t.load(d)})}}(a,d),l.show=function(e,n){return function({scene:r,options:t={ssr:!1}},...s){const{shortcutMngr:o,askForPromise:c,log:i,findInstructions:u,setInstruction:d}=e,l=c(),a=c(),{opened:p,scenes:h,sceneNames:f,currentPage:m}=n;if(m){const e=h[m].beforeHide;"function"==typeof e&&e({done:a.done,dependencies:o.getDependencies()})}else a.done(!0);return a.onComplete(e=>{if(!e)return l.done(),l.promise;if(!f.has(r)&&i)return i({message:`Scene ${r} is not available.`,level:1,type:"error"}),l.done(),l.promise;if(!p&&t.ssr)return n.opened=!0,n.currentPage=r,o.changeContext(r),l.done(),l.promise;const{show:a,parents:m=[]}=h[r];if("*"===m[0])return a().then(()=>l.done()),n.currentParents.push(n.currentPage),n.currentPage=r,l.promise;function g([e,r]){if("show"===r)n.currentScene&&n.currentParents.push(n.currentScene),n.currentScene=e;else{let e=n.currentParents.pop();n.currentScene=e}return h[e][r]}m.forEach(e=>f.has(e)),n.currentParents||(n.currentParents=[]);const y=u(n.currentScene,n.currentParents,r,m),S=[];for(let e of y)[e].map(g).map(e=>S.push(d(e),...s));c.sequence(S).onComplete(()=>{n.opened=!0,o.changeContext(r),"function"==typeof h[r].afterShow&&h[r].afterShow({dependencies:o.getDependencies(),done:()=>{}}),l.done()})}),l.promise}}(a,d),l.jump=function(e,n){return function({scene:r},...t){return e.jumpStack.push(e.currentScene),n({scene:r},...t)}}(d,l.show),l.jumpBack=function(e,n){return function({hops:r}={hops:1},...t){for(let n=0;n<r-1;n++)e.jumpStack.pop();if(0===e.jumpStack.length)return;const s=e.jumpStack.pop();return n({scene:s},...t)}}(d,l.show),l.jumpsReset=function(e){return function(){e.jumpStack=[]}}(d),l.loadPlugins=async function(e){const n=e.map(e=>`plugin${e}`),r=await import("@peter.naydenov/shortcuts");return n.map(e=>r[e])},l.setDependencies=e=>c.setDependencies(e),l.getDependencies=()=>c.getDependencies(),l.setNote=n=>e.shortcuts.setNote(n),l.listScenes=()=>[...d.sceneNames],l.enablePlugin=(e,n)=>c.enablePlugin(e,n),l.disablePlugin=e=>c.disablePlugin(e),l.emit=(e,...n)=>c.emit(e,...n),l};
1
+ "use strict";var e=require("@peter.naydenov/shortcuts"),n=require("ask-for-promise"),r=require("@peter.naydenov/log");function*t(e,n,r,t){let s=null,o=!0;if(null===e)return yield*t.map(e=>[e,"show"]),void(yield[r,"show"]);if(0!==t.length){if(t.includes(e)){for(let n=t.indexOf(e)+1;n<t.length;n++)yield[t[n],"show"];return void(yield[r,"show"])}if(!n)return yield[e,"hide"],void(yield*t.map(e=>[e,"show"]));if(t.every((e,r)=>n[r]===t[r]&&(s=r,!0)),null==s)return yield[e,"hide"],n.reverse(),yield*n.map(e=>[e,"hide"]),yield*t.map(e=>[e,"show"]),void(yield[r,"show"]);yield[e,"hide"];for(let e=n.length;e>s+1;e--)yield[n[e-1],"hide"];for(let e=s+1;e<t.length;e++)yield[t[e],"show"];yield[r,"show"]}else{if(yield[e,"hide"],n.includes(r)){let e=n.indexOf(r),t=n.filter((n,r)=>r>e);t.reverse(),yield*t.map(e=>[e,"hide"]),o=!1}else{let e=[...n];e.reverse(),yield*e.map(e=>[e,"hide"])}o&&(yield[r,"show"])}}function s(e){return function(n,...r){const{askForPromise:t,deps:s}=e;return function(){const e=t();return n({task:e,dependencies:s()},...r),e.promise}}}module.exports=function(o={logLevel:0}){const c=e.shortcuts({errorEventName:"@app-error"}),i=o.logLevel||1,u=r({level:i},e=>{const{type:n}=e;"error"===n&&c.emit("@app-error",e)}),l={currentScene:null,currentParents:null,sceneNames:new Set,scenes:{},opened:!1,jumpStack:[]},d={},a={shortcutMngr:c,findInstructions:t,askForPromise:n,setInstruction:s({askForPromise:n,deps:c.getDependencies}),log:u};return d.hide=function(e,n){return function(r=1){const{askForPromise:t,shortcutMngr:s,setInstruction:o}=e,{currentScene:c,currentParents:i,scenes:u}=n,l=t(),d=[],a=i.length>0;let p;return s.pause(),d.push(o(u[c].hide)),a||(n.currentScene=null),a&&"*"===r&&[...i].reverse().forEach(e=>{p=n.currentParents.at(-1),n.currentScene=p,d.push(o(u[e].hide))}),a&&!["*",1].includes(r)&&i.slice("-"+(r-1)).reverse().map(e=>{p=n.currentParents.at(-1),n.currentScene=p,d.push(o(u[e].hide))}),(r=t.sequence(d)).onComplete(()=>{s.changeContext(n.currentScene),l.done()}),l.promise}}(a,l),d.listShortcuts=function(e,n){return function(e){const{scenes:r,sceneNames:t}=n;if(!t.has(e))return null;const{show:s,hide:o,parents:c,beforeUnload:i,afterLoad:u,...l}=r[e];return Object.keys(l)}}(0,l),d.setScenes=function(e,n){return function(r){const{shortcutMngr:t,log:s}=e;r.forEach(e=>{if(null==e)return;const{name:r,scene:o}=e;if(!r)return void s({message:"Scene name is not defined",level:1,type:"error"});if(null==o)return void s({message:`Scene ${r} is not defined`,level:1,type:"error"});o.parents||(o.parents=[]),n.scenes[r]=o,n.sceneNames.add(r);const{show:c,hide:i,parents:u,...l}=o,d={};d[r]=l,t.load(d)})}}(a,l),d.show=function(e,n){return function({scene:r,options:t={ssr:!1}},...s){const{shortcutMngr:o,askForPromise:c,log:i,findInstructions:u,setInstruction:l}=e,d=c(),a=c(),{opened:p,scenes:h,sceneNames:f,currentScene:m}=n;return m&&"function"==typeof h[m].beforeHide?(0,h[m].beforeHide)({done:a.done,dependencies:o.getDependencies()}):a.done(!0),a.onComplete(e=>{if(!e)return d.done(),d.promise;if(!f.has(r))return i({message:`Scene "${r}" is not available.`,level:1,type:"error"}),d.done(),d.promise;if(!p&&t.ssr)return n.opened=!0,n.currentScene=r,o.changeContext(r),d.done(),d.promise;const{show:a,parents:m=[]}=h[r];if("*"===m[0])return l(a,...s)().then(()=>d.done()),n.currentParents.push(n.currentScene),n.currentScene=r,d.promise;if(0!==m.length&&!m.every(e=>f.has(e)))return i({message:`Some of '${r}' parent scenes are not set.`,level:1,type:"error"}),d.done(),d.promise;function g([e,r]){if("show"===r)n.currentScene&&(n.currentParents=[...h[n.currentScene].parents]),n.currentScene=e;else{let r=h[e].parents.at(-1);n.currentScene=r}return h[e][r]}n.currentParents||(n.currentParents=[]);const S=u(n.currentScene,n.currentParents,r,m),y=[];for(let e of S){const n=g(e);y.push(l(n,...s))}c.sequence(y).onComplete(()=>{n.opened=!0,n.currentScene=r,n.currentParents=h[r].parents||null,o.changeContext(r),"function"==typeof h[r].afterShow&&h[r].afterShow({dependencies:o.getDependencies(),done:()=>{}}),d.done()})}),d.promise}}(a,l),d.jump=function(e,n){return function({scene:r},...t){return e.jumpStack.push(e.currentScene),n({scene:r},...t)}}(l,d.show),d.jumpBack=function(e,n){return function({hops:r}={hops:1},...t){for(let n=0;n<r-1;n++)e.jumpStack.pop();if(0===e.jumpStack.length)return;const s=e.jumpStack.pop();return n({scene:s},...t)}}(l,d.show),d.jumpsReset=function(e){return function(){e.jumpStack=[]}}(l),d.loadPlugins=async function(e){const n=e.map(e=>`plugin${e}`),r=await import("@peter.naydenov/shortcuts");return n.map(e=>r[e])},d.setDependencies=e=>c.setDependencies(e),d.getDependencies=()=>c.getDependencies(),d.setNote=n=>e.shortcuts.setNote(n),d.listScenes=()=>[...l.sceneNames],d.enablePlugin=(e,n)=>c.enablePlugin(e,n),d.disablePlugin=e=>c.disablePlugin(e),d.getState=()=>({scene:l.currentScene,parents:l.currentParents,opened:l.opened}),d.emit=(e,...n)=>c.emit(e,...n),d};
package/dist/cuts.esm.mjs CHANGED
@@ -1 +1 @@
1
- import{shortcuts as e}from"@peter.naydenov/shortcuts";import n from"ask-for-promise";import r from"@peter.naydenov/log";function*t(e,n,r,t){let s=null;if(null===e)return yield*t.map(e=>[e,"show"]),void(yield[r,"show"]);if(!t||0===t.length)return n?(yield[e,"hide"],n.reverse(),yield*n.map(e=>[e,"hide"]),void(yield[r,"show"])):(yield[e,"hide"],void(yield[r,"show"]));if(t.includes(e)){for(let n=t.indexOf(e)+1;n<t.length;n++)yield[t[n],"show"];return void(yield[r,"show"])}if(!n)return yield[e,"hide"],void(yield*t.map(e=>[e,"show"]));if(t.every((e,r)=>n[r]===t[r]&&(s=r,!0)),null==s)return yield[e,"hide"],n.reverse(),yield*n.map(e=>[e,"hide"]),yield*t.map(e=>[e,"show"]),void(yield[r,"show"]);yield[e,"hide"];for(let e=n.length;e>s+1;e--)yield[n[e-1],"hide"];for(let e=s+1;e<t.length;e++)yield[t[e],"show"];yield[r,"show"]}function s(e){return function(n,...r){const{askForPromise:t,deps:s}=e;return function(){const e=t();return n({task:e,dependencies:s()},...r),e.promise}}}function o(o={logLevel:0}){const c=e({errorEventName:"@app-error"}),i=o.logLevel||0,u=r({level:i}),d={currentScene:null,currentParents:null,sceneNames:new Set,scenes:{},opened:!1,jumpStack:[]},l={},a={shortcutMngr:c,findInstructions:t,askForPromise:n,setInstruction:s({askForPromise:n,deps:c.getDependencies}),log:u};return l.hide=function(e,n){return function(r=1){const{askForPromise:t,shortcutMngr:s,setInstruction:o}=e,{currentScene:c,currentParents:i,scenes:u}=n,d=t(),l=[],a=i.length>0;let p;return s.pause(),l.push(o(u[c].hide)),a||(n.currentScene=null),a&&"*"===r&&[...i].reverse().forEach(e=>{p=n.currentParents.pop(),n.currentScene=p,l.push(o(u[e].hide))}),a&&!["*",1].includes(r)&&i.slice("-"+(r-1)).reverse().map(e=>{p=n.currentParents.pop(),n.currentScene=p,l.push(o(u[e].hide))}),(r=t.sequence(l)).onComplete(()=>{s.changeContext(n.currentScene),d.done()}),d.promise}}(a,d),l.listShortcuts=function(e,n){return function(e){const{scenes:r,sceneNames:t}=n;if(!t.has(e))return null;const{show:s,hide:o,parents:c,beforeUnload:i,afterLoad:u,...d}=r[e];return Object.keys(d)}}(0,d),l.setScenes=function(e,n){return function(r){const{shortcutMngr:t}=e;r.forEach(e=>{if(null==e)return;const{name:r,scene:s}=e;if(null==s)return void console.warn(`Scene ${r} is not defined`);s.parents||(s.parents=[]),n.scenes[r]=s,n.sceneNames.add(r);const{show:o,hide:c,parents:i,...u}=s,d={};d[r]=u,t.load(d)})}}(a,d),l.show=function(e,n){return function({scene:r,options:t={ssr:!1}},...s){const{shortcutMngr:o,askForPromise:c,log:i,findInstructions:u,setInstruction:d}=e,l=c(),a=c(),{opened:p,scenes:h,sceneNames:f,currentPage:m}=n;if(m){const e=h[m].beforeHide;"function"==typeof e&&e({done:a.done,dependencies:o.getDependencies()})}else a.done(!0);return a.onComplete(e=>{if(!e)return l.done(),l.promise;if(!f.has(r)&&i)return i({message:`Scene ${r} is not available.`,level:1,type:"error"}),l.done(),l.promise;if(!p&&t.ssr)return n.opened=!0,n.currentPage=r,o.changeContext(r),l.done(),l.promise;const{show:a,parents:m=[]}=h[r];if("*"===m[0])return a().then(()=>l.done()),n.currentParents.push(n.currentPage),n.currentPage=r,l.promise;function g([e,r]){if("show"===r)n.currentScene&&n.currentParents.push(n.currentScene),n.currentScene=e;else{let e=n.currentParents.pop();n.currentScene=e}return h[e][r]}m.forEach(e=>f.has(e)),n.currentParents||(n.currentParents=[]);const y=u(n.currentScene,n.currentParents,r,m),S=[];for(let e of y)[e].map(g).map(e=>S.push(d(e),...s));c.sequence(S).onComplete(()=>{n.opened=!0,o.changeContext(r),"function"==typeof h[r].afterShow&&h[r].afterShow({dependencies:o.getDependencies(),done:()=>{}}),l.done()})}),l.promise}}(a,d),l.jump=function(e,n){return function({scene:r},...t){return e.jumpStack.push(e.currentScene),n({scene:r},...t)}}(d,l.show),l.jumpBack=function(e,n){return function({hops:r}={hops:1},...t){for(let n=0;n<r-1;n++)e.jumpStack.pop();if(0===e.jumpStack.length)return;const s=e.jumpStack.pop();return n({scene:s},...t)}}(d,l.show),l.jumpsReset=function(e){return function(){e.jumpStack=[]}}(d),l.loadPlugins=async function(e){const n=e.map(e=>`plugin${e}`),r=await import("@peter.naydenov/shortcuts");return n.map(e=>r[e])},l.setDependencies=e=>c.setDependencies(e),l.getDependencies=()=>c.getDependencies(),l.setNote=n=>e.setNote(n),l.listScenes=()=>[...d.sceneNames],l.enablePlugin=(e,n)=>c.enablePlugin(e,n),l.disablePlugin=e=>c.disablePlugin(e),l.emit=(e,...n)=>c.emit(e,...n),l}export{o as default};
1
+ import{shortcuts as e}from"@peter.naydenov/shortcuts";import n from"ask-for-promise";import r from"@peter.naydenov/log";function*t(e,n,r,t){let s=null,o=!0;if(null===e)return yield*t.map(e=>[e,"show"]),void(yield[r,"show"]);if(0!==t.length){if(t.includes(e)){for(let n=t.indexOf(e)+1;n<t.length;n++)yield[t[n],"show"];return void(yield[r,"show"])}if(!n)return yield[e,"hide"],void(yield*t.map(e=>[e,"show"]));if(t.every((e,r)=>n[r]===t[r]&&(s=r,!0)),null==s)return yield[e,"hide"],n.reverse(),yield*n.map(e=>[e,"hide"]),yield*t.map(e=>[e,"show"]),void(yield[r,"show"]);yield[e,"hide"];for(let e=n.length;e>s+1;e--)yield[n[e-1],"hide"];for(let e=s+1;e<t.length;e++)yield[t[e],"show"];yield[r,"show"]}else{if(yield[e,"hide"],n.includes(r)){let e=n.indexOf(r),t=n.filter((n,r)=>r>e);t.reverse(),yield*t.map(e=>[e,"hide"]),o=!1}else{let e=[...n];e.reverse(),yield*e.map(e=>[e,"hide"])}o&&(yield[r,"show"])}}function s(e){return function(n,...r){const{askForPromise:t,deps:s}=e;return function(){const e=t();return n({task:e,dependencies:s()},...r),e.promise}}}function o(o={logLevel:0}){const c=e({errorEventName:"@app-error"}),i=o.logLevel||1,u=r({level:i},e=>{const{type:n}=e;"error"===n&&c.emit("@app-error",e)}),l={currentScene:null,currentParents:null,sceneNames:new Set,scenes:{},opened:!1,jumpStack:[]},a={},d={shortcutMngr:c,findInstructions:t,askForPromise:n,setInstruction:s({askForPromise:n,deps:c.getDependencies}),log:u};return a.hide=function(e,n){return function(r=1){const{askForPromise:t,shortcutMngr:s,setInstruction:o}=e,{currentScene:c,currentParents:i,scenes:u}=n,l=t(),a=[],d=i.length>0;let p;return s.pause(),a.push(o(u[c].hide)),d||(n.currentScene=null),d&&"*"===r&&[...i].reverse().forEach(e=>{p=n.currentParents.at(-1),n.currentScene=p,a.push(o(u[e].hide))}),d&&!["*",1].includes(r)&&i.slice("-"+(r-1)).reverse().map(e=>{p=n.currentParents.at(-1),n.currentScene=p,a.push(o(u[e].hide))}),(r=t.sequence(a)).onComplete(()=>{s.changeContext(n.currentScene),l.done()}),l.promise}}(d,l),a.listShortcuts=function(e,n){return function(e){const{scenes:r,sceneNames:t}=n;if(!t.has(e))return null;const{show:s,hide:o,parents:c,beforeUnload:i,afterLoad:u,...l}=r[e];return Object.keys(l)}}(0,l),a.setScenes=function(e,n){return function(r){const{shortcutMngr:t,log:s}=e;r.forEach(e=>{if(null==e)return;const{name:r,scene:o}=e;if(!r)return void s({message:"Scene name is not defined",level:1,type:"error"});if(null==o)return void s({message:`Scene ${r} is not defined`,level:1,type:"error"});o.parents||(o.parents=[]),n.scenes[r]=o,n.sceneNames.add(r);const{show:c,hide:i,parents:u,...l}=o,a={};a[r]=l,t.load(a)})}}(d,l),a.show=function(e,n){return function({scene:r,options:t={ssr:!1}},...s){const{shortcutMngr:o,askForPromise:c,log:i,findInstructions:u,setInstruction:l}=e,a=c(),d=c(),{opened:p,scenes:f,sceneNames:h,currentScene:m}=n;return m&&"function"==typeof f[m].beforeHide?(0,f[m].beforeHide)({done:d.done,dependencies:o.getDependencies()}):d.done(!0),d.onComplete(e=>{if(!e)return a.done(),a.promise;if(!h.has(r))return i({message:`Scene "${r}" is not available.`,level:1,type:"error"}),a.done(),a.promise;if(!p&&t.ssr)return n.opened=!0,n.currentScene=r,o.changeContext(r),a.done(),a.promise;const{show:d,parents:m=[]}=f[r];if("*"===m[0])return l(d,...s)().then(()=>a.done()),n.currentParents.push(n.currentScene),n.currentScene=r,a.promise;if(0!==m.length&&!m.every(e=>h.has(e)))return i({message:`Some of '${r}' parent scenes are not set.`,level:1,type:"error"}),a.done(),a.promise;function g([e,r]){if("show"===r)n.currentScene&&(n.currentParents=[...f[n.currentScene].parents]),n.currentScene=e;else{let r=f[e].parents.at(-1);n.currentScene=r}return f[e][r]}n.currentParents||(n.currentParents=[]);const S=u(n.currentScene,n.currentParents,r,m),y=[];for(let e of S){const n=g(e);y.push(l(n,...s))}c.sequence(y).onComplete(()=>{n.opened=!0,n.currentScene=r,n.currentParents=f[r].parents||null,o.changeContext(r),"function"==typeof f[r].afterShow&&f[r].afterShow({dependencies:o.getDependencies(),done:()=>{}}),a.done()})}),a.promise}}(d,l),a.jump=function(e,n){return function({scene:r},...t){return e.jumpStack.push(e.currentScene),n({scene:r},...t)}}(l,a.show),a.jumpBack=function(e,n){return function({hops:r}={hops:1},...t){for(let n=0;n<r-1;n++)e.jumpStack.pop();if(0===e.jumpStack.length)return;const s=e.jumpStack.pop();return n({scene:s},...t)}}(l,a.show),a.jumpsReset=function(e){return function(){e.jumpStack=[]}}(l),a.loadPlugins=async function(e){const n=e.map(e=>`plugin${e}`),r=await import("@peter.naydenov/shortcuts");return n.map(e=>r[e])},a.setDependencies=e=>c.setDependencies(e),a.getDependencies=()=>c.getDependencies(),a.setNote=n=>e.setNote(n),a.listScenes=()=>[...l.sceneNames],a.enablePlugin=(e,n)=>c.enablePlugin(e,n),a.disablePlugin=e=>c.disablePlugin(e),a.getState=()=>({scene:l.currentScene,parents:l.currentParents,opened:l.opened}),a.emit=(e,...n)=>c.emit(e,...n),a}export{o as default};
package/dist/cuts.umd.js CHANGED
@@ -1 +1 @@
1
- !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).cuts=t()}(this,function(){"use strict";var e={_normalizeWithPlugins:function(e,t){return function(e){const n=t.shortcuts;Object.keys(n).forEach(t=>{Object.entries(n[t]).forEach(([o,r])=>{const s=e(o);s!==o&&(delete n[t][o],n[t][s]=r)})})}},_readShortcutWithPlugins:function(e,t){return function(n){const{inAPI:o}=e,r=n.split(":")[0].toLowerCase().trim(),s=o._systemAction(r,"none");let i=n;return-1!==s&&(i=t.plugins[s].shortcutName(n)),i}},_systemAction:function(e,t){return function(e,n,o=null){return t.plugins.findIndex(t=>t.getPrefix()===e&&(t[n]&&t[n](o),!0))}},changeContext:function(e,t){const{shortcuts:n,currentContext:o,ERROR_EVENT_NAME:r}=t,{ev:s}=e;return function(e=!1){const i=o.name;if(!e)return s.reset(),void(o.name=null);i!==e&&(n[e]?(n[i]&&s.reset(),o.name=e,t.plugins.forEach(t=>t.contextChange(e)),Object.entries(n[e]).forEach(([e,t])=>{t.forEach(t=>s.on(e,t))}),s.on("*",(...e)=>{t.exposeShortcut&&t.exposeShortcut(...e)})):s.emit(r,`Context '${e}' does not exist`))}},listShortcuts:function(e,t){const n=t.shortcuts;return function(e=null){if(null!=e){let t=n[e];return null==t?null:Object.entries(t).map(([e,t])=>e)}return Object.keys(n).map(e=>{let t={};return t.context=e,t.shortcuts=Object.entries(n[e]).map(([e,t])=>e),t})}},load:function(e,t){const{shortcuts:n,plugins:o}=t,{API:{changeContext:r,getContext:s}}=e;return function(e){const t=s(),i=o.map(e=>e.getPrefix().toUpperCase());let c=!1;Object.entries(e).forEach(([e,r])=>{e===t&&(c=!0),n[e]={},Object.entries(r).forEach(([t,r])=>{let s=t,c=t.toUpperCase().trim(),u=i.map((e,t)=>c.startsWith(e)?t:null).filter(e=>null!==e);if(u.length){let e=u[0];s=o[e].shortcutName(t)}r instanceof Function&&(r=[r]),n[e][s]=r})}),c&&(r(),r(t))}},unload:function(e,t){const{currentContext:n,shortcuts:o,ERROR_EVENT_NAME:r}=t,{ev:s}=e;return function(e){n.name!==e?o[e]?delete o[e]:s.emit(r,`Context '${e}' does not exist`):s.emit(r,`Context '${e}' can't be removed during is current active context. Change the context first`)}}};function t(e){const t=e.toUpperCase(),n=/KEY\s*\:/i.test(t),o=t.indexOf(":");return n?`KEY:${t.slice(o+1).split(",").map(e=>e.trim()).map(e=>e.split("+").map(e=>e.trim()).sort().join("+")).join(",")}`:e}function n(e,t){let{shiftKey:n,altKey:o,ctrlKey:r}=e,s=t(),i=e.code.replace("Key","").replace("Digit",""),c=[];return r&&c.push("CTRL"),n&&c.push("SHIFT"),o&&c.push("ALT"),s.hasOwnProperty(i)?c.push(s[i].toUpperCase()):["ControlLeft","ControlRight","ShiftLeft","ShiftRight","AltLeft","AltRight","Meta"].includes(i)||c.push(i.toUpperCase()),c.sort()}function o(e,t){let n=0;const{regex:o}=e,{listenOptions:r,currentContext:{name:s},shortcuts:i}=t;return null==s?0:(Object.entries(i[s]).forEach(([e,t])=>{if(!o.test(e))return;n++;let s=e.slice(4).split(",").length;r.maxSequence<s&&(r.maxSequence=s)}),n)}function r(){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(e,t,n){const{listenOptions:{clickTarget:o}}=t;let r=n;return r===document||r===document.body?null:r.dataset[o]||"A"===r.nodeName?r:s(e,t,r.parentNode)}function i(e){const t=e.toUpperCase(),n=/CLICK\s*\:/i.test(t),o=["LEFT","MIDDLE","RIGHT"],r=["ALT","SHIFT","CTRL"];let s=null,i=[],c=0,u=t.indexOf(":");return n?(t.slice(u+1).trim().split("-").map(e=>e.trim()).forEach(e=>{o.includes(e)?s=e:r.includes(e)?i.push(e):isNaN(e)||(c=e)}),`CLICK:${s}-${c}${i.length>0?"-":""}${i.sort().join("-")}`):e}function c(e,t){let{shiftKey:n,altKey:o,ctrlKey:r,key:s,button:i}=e,c=`CLICK:${["LEFT","MIDDLE","RIGHT"][i]}-${t}`,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 u(e,t){let n=0;const{regex:o}=e,{listenOptions:r,currentContext:{name:s},shortcuts:i}=t;return null==s?0:(Object.entries(i[s]).forEach(([e,t])=>{if(!o.test(e))return;n++;let[,s]=e.slice(6).split("-");r.maxClicks<s&&(r.maxClicks=s)}),n)}function l(e){const t=e.toUpperCase(),n=/FORM\s*\:/i.test(t),o=t.indexOf(":");return n?`FORM:${t.slice(o+1).trim()}`:e}function a(e,t){const{regex:n,_defaults:o,ev:r}=e,{currentContext:{name:s},shortcuts:i,callbacks:c}=t;let u=[],l=[],a=[];if(null==s)return!1;if(Object.entries(i[s]).forEach(([e,t])=>{n.test(e)&&("FORM:WATCH"===e&&(u=t),"FORM:DEFINE"===e&&(l=t),"FORM:ACTION"===e&&(a=t))}),0===a.length)return!1;let f=new Set;0===l.length&&(l=[o.define]),0===u.length&&(u=[o.watch]);let p=u.map(e=>e()).reduce((e,t)=>(e.push(t),e),[]);return t.watchList=document.querySelectorAll(p),t.watchList.forEach(e=>f.add(l[0](e))),t.typeFn=l[0]?l[0]:o.define,a.forEach(e=>e instanceof Function?e()instanceof Array?void e().forEach(({fn:e,type:n,timing:o,wait:s=0})=>{if(f.has(n)&&e instanceof Function){let t=`${n}/${o}`;const s=c.hasOwnProperty(t);s?c[t].push(e):c[t]=[e],s||r.on(t,(e,t)=>{t.forEach(t=>{t instanceof Function&&t(e)})})}"instant"===o&&(t.wait[`${n}`]=s)}):(console.warn("Warning: The 'form:action' function should RETURN an array."),!1):(console.warn("Warning: The 'form:action' should be a function."),!1)),Object.keys(t.callbacks).length>0}const f={watch:()=>"input, select, textarea, button, a",define:e=>"checkbox"===e.type||"radio"===e.type?"checkbox":"button"==e.type||"submit"==e.type?"button":"input"};function p(t={}){let n={},o={};const r=function(){let e={"*":[]},t={},n=new Set,o=!1,r="";return{on:function(t,n){e[t]||(e[t]=[]),e[t].push(n)},once:function(e,n){"*"!==e&&(t[e]||(t[e]=[]),t[e].push(n))},off:function(n,o){if(o)return e[n]&&(e[n]=e[n].filter(e=>e!==o)),t[n]&&(t[n]=t[n].filter(e=>e!==o)),e[n]&&0===e[n].length&&delete e[n],void(t[n]&&0===t[n].length&&delete e[n]);t[n]&&delete t[n],e[n]&&delete e[n]},reset:function(){e={"*":[]},t={},n=new Set},emit:function(){const[s,...i]=arguments;function c(t){let o=!1;"*"!==t&&(n.has(t)||(e[t].every(e=>{const t=e(...i);return"string"!=typeof t||"STOP"!==t.toUpperCase()||(o=!0,!1)}),o||e["*"].forEach(e=>e(s,...i))))}if(o&&(console.log(`${r} Event "${s}" was triggered.`),i.length>0&&(console.log("Arguments:"),console.log(...i),console.log("^----"))),"*"!==s){if(t[s]){if(n.has(s))return;t[s].forEach(e=>e(...i)),delete t[s]}e[s]&&c(s)}else Object.keys(e).forEach(e=>c(e))},stop:function(o){if("*"===o){const o=Object.keys(e),r=Object.keys(t);return void(n=new Set([...r,...o]))}n.add(o)},start:function(e){"*"!==e?n.delete(e):n.clear()},debug:function(e,t){o=!!e,t&&"string"==typeof t&&(r=t)}}}(),s={currentContext:{name:null,note:null},shortcuts:{},plugins:[],exposeShortcut:!(!t.onShortcut||"function"!=typeof t.onShortcut)&&t.onShortcut,ERROR_EVENT_NAME:t.errorEventName?t.errorEventName:"@shortcuts-error"};let i={ev:r,inAPI:n,API:o,extra:{}};return o.enablePlugin=(e,t={})=>{if("function"!=typeof e)return;let o=e(i,s,t);const r=o.getPrefix();-1===n._systemAction(r,"none")?s.plugins.push(o):o.destroy()},o.disablePlugin=e=>{const t=n._systemAction(e,"destroy");-1!==t&&(s.plugins=s.plugins.filter((e,n)=>n!==t))},o.mutePlugin=e=>n._systemAction(e,"mute"),o.unmutePlugin=e=>n._systemAction(e,"unmute"),o.listPlugins=()=>s.plugins.map(e=>e.getPrefix()),o.getContext=()=>s.currentContext.name,o.getNote=()=>s.currentContext.note,o.setNote=(e=null)=>{"string"!=typeof e&&null!=e||(s.currentContext.note=e)},o.pause=(e="*")=>{let t=n._readShortcutWithPlugins(e);r.stop(t)},o.resume=(e="*")=>{const t=n._readShortcutWithPlugins(e);r.start(t)},o.emit=(e,...t)=>r.emit(n._readShortcutWithPlugins(e),...t),o.listContexts=()=>Object.keys(s.shortcuts),o.setDependencies=e=>i.extra={...i.extra,...e},o.getDependencies=()=>i.extra,o.reset=function(){r.reset(),o.changeContext(),s.plugins.forEach(e=>e.destroy()),o.listContexts().map(e=>o.unload(e)),i.extra={},s.exposeShortcut=null},Object.entries(e).forEach(([e,t])=>{e.startsWith("_")?n[e]=t(i,s):o[e]=t(i,s)}),o}var m=Object.freeze({__proto__:null,pluginClick:function(e,t,n){let{currentContext:o,shortcuts:r}=t,{inAPI:l}=e,a={ev:e.ev,_findTarget:s,_readClickEvent:c,mainDependencies:e,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"}};l._normalizeWithPlugins(i);let p=function(e,t){const{ev:n,_findTarget:o,_readClickEvent:r,mainDependencies:s}=e,{listenOptions:i,currentContext:c}=t,{mouseWait:u}=i;let l=null,a=null,f=null,p=null,m=0;function d(){const e=r(a,m),t={target:l,targetProps:l?l.getBoundingClientRect():null,x:a.clientX,y:a.clientY,context:c.name,note:c.note,event:a,dependencies:s.extra,type:"click"};n.emit(e,t),f=null,p=null,l=null,a=null,m=0}function h(n){let r=i.maxClicks;return clearTimeout(f),p?(clearTimeout(p),void(p=setTimeout(()=>p=null,u))):(l=o(e,t,n.target),l&&l.dataset.hasOwnProperty("quickClick")&&(r=1),l&&"A"===l.tagName&&(r=1),a=n,m++,m>=r?(d(),void(r>1&&(p=setTimeout(()=>p=null,u)))):void(f=setTimeout(d,u)))}function g(n){let r=i.maxClicks;return clearTimeout(f),p?(clearTimeout(p),void(p=setTimeout(()=>p=null,u))):(l=o(e,t,n.target),l&&l.dataset.hasOwnProperty("quickClick")&&(r=1),l&&"A"===l.tagName&&(r=1),a=n,m++,m>=r?(d(),void(r>1&&(p=setTimeout(()=>p=null,u)))):void(f=setTimeout(d,u)))}return{start:function(){t.active||(window.addEventListener("contextmenu",g),document.addEventListener("click",h),t.active=!0)},stop:function(){t.active&&(window.removeEventListener("contextmenu",g),document.removeEventListener("click",h),t.active=!1,f&&(clearTimeout(f),f=null),p&&(clearTimeout(p),p=null),m=0)}}}(a,f),m=u(a,f);m>0&&p.start();let d={getPrefix:()=>"click",shortcutName:e=>i(e),contextChange:()=>{m=u(a,f),m<1&&p.stop(),m>0&&p.start()},mute:()=>{p.stop()},unmute:()=>p.start(),destroy:()=>p.stop()};return Object.freeze(d),d},pluginForm:function(e,t,n){let{currentContext:o,shortcuts:r}=t,{inAPI:s}=e,i={ev:e.ev,mainDependencies:e,regex:/FORM\s*\:/i,_defaults:f},c={currentContext:o,shortcuts:r,callbacks:{},typeFn:"",watchList:[],wait:{}};s._normalizeWithPlugins(l);let u=function(e,t){const{ev:n}=e;let o=null;function r(e,t,n,o){return{target:n.target,context:t.currentContext.name,note:t.currentContext.note,event:n,dependencies:e.mainDependencies.extra,type:o}}function s(o){const{callbacks:s,typeFn:i}=t,c=i(o.target),u=r(e,t,o,c),l=`${c}/in`;null!=s[l]&&n.emit(l,u,s[l])}function i(o){const{callbacks:s,typeFn:i}=t,c=r(e,t,o,"form-out"),u=`${i(o.target)}/out`;null!=s[u]&&n.emit(u,c,s[u])}function c(s){const{callbacks:i,typeFn:c}=t,u=r(e,t,s,"form-instant"),l=c(s.target),a=t.wait[`${l}`],f=`${l}/instant`;null!=i[f]&&(0!==a?(clearTimeout(o),o=setTimeout(()=>n.emit(f,u,i[f]),a)):n.emit(f,u,i[f]))}return{start:function(){t.active||(document.addEventListener("focusin",s),document.addEventListener("focusout",i),document.addEventListener("input",c),t.active=!0)},stop:function(){t.active&&(document.removeEventListener("focusin",s),document.removeEventListener("focusout",i),document.removeEventListener("input",c),t.active=!1)}}}(i,c);o.name&&a(i,c)&&u.start();let p={getPrefix:()=>"form",shortcutName:e=>l(e),contextChange:()=>{c.callbacks={},c.typeFn="",c.watchList=[],c.wait={},a(i,c)?u.start():u.stop()},mute:()=>u.stop(),unmute:()=>u.start(),destroy:()=>{u.stop()}};return Object.freeze(p),p},pluginKey:function(e,s,i={}){let{currentContext:c,shortcuts:u,exposeShortcut:l}=s,{inAPI:a}=e,f={ev:e.ev,_specialChars:r,_readKeyEvent:n,mainDependencies:e,regex:/KEY\s*\:/i},p={currentContext:c,shortcuts:u,active:!1,listenOptions:{keyWait:i.keyWait?i.keyWait:480,maxSequence:1,keyIgnore:null},streamKeys:!(!i.streamKeys||"function"!=typeof i.streamKeys)&&i.streamKeys};a._normalizeWithPlugins(t);let m=function(e,t){const{ev:n,_specialChars:o,_readKeyEvent:r,mainDependencies:s}=e,{currentContext:i,streamKeys:c,listenOptions:u}=t,{keyWait:l}=u;let a=[],f=null,p=!0,m=!1;const d=()=>p=!1,h=()=>p=!0,g=()=>m=!0,y=()=>!1===p;function v(){let e=a.map(e=>[e.join("+")]);const t={wait:d,end:h,ignore:g,isWaiting:y,note:i.note,context:i.name,dependencies:s.extra,type:"key"};if(!p){let o=e.at(-1);n.emit(o,t),m&&(e=e.slice(0,-1),m=!1)}if(p){const o=`KEY:${e.join(",")}`;n.emit(o,t),a=[],f=null}}function x(t){if(clearTimeout(f),o().hasOwnProperty(t.code))return a.push(r(t,o)),c&&c({key:t.key,context:i.name,note:i.note,dependencies:e.extra}),u.keyIgnore?(clearTimeout(u.keyIgnore),void(u.keyIgnore=setTimeout(()=>u.keyIgnore=null,l))):p&&a.length===u.maxSequence?(v(),void(u.keyIgnore=setTimeout(()=>u.keyIgnore=null,l))):void(p?f=setTimeout(v,l):v())}function k(t){if(!o().hasOwnProperty(t.code)){if(clearTimeout(f),c&&c({key:t.key,context:i.name,note:i.note,dependencies:e.extra}),u.keyIgnore)return clearTimeout(u.keyIgnore),void(u.keyIgnore=setTimeout(()=>u.keyIgnore=null,l));if(a.push(r(t,o)),p&&a.length===u.maxSequence)return v(),void(u.keyIgnore=setTimeout(()=>u.keyIgnore=null,l));p?f=setTimeout(v,l):v()}}return{start:function(){t.active||(document.addEventListener("keydown",x),document.addEventListener("keypress",k),t.active=!0)},stop:function(){t.active&&(document.removeEventListener("keydown",x),document.removeEventListener("keypress",k),t.active=!1,f&&(clearTimeout(f),f=null),u.keyIgnore&&(clearTimeout(u.keyIgnore),u.keyIgnore=null),a=[],p=!0,m=!1)}}}(f,p),d=o(f,p);d>0&&m.start();let h={getPrefix:()=>"key",shortcutName:e=>t(e),contextChange:e=>{d=o(f,p),d<1&&m.stop(),d>0&&m.start()},mute:()=>m.stop(),unmute:()=>m.start(),destroy:()=>m.stop()};return Object.freeze(h),h},shortcuts:p});function d(e){return e?function(e){let t=e.map(e=>h()),n=t.map(e=>e.promise);t.promises=t;let o=g(Promise.all(n));function r(e){let t="pending";return e.then(()=>t="fulfilled").catch(()=>t="rejected"),t}function s(n,...o){t.forEach((t,s)=>n({value:e[s],done:t.done,cancel:t.cancel,timeout:t.timeout,state:r(t.promise)},...o))}const i={promise:Promise.all(n),promises:t,done:e=>{t.forEach(t=>t.done(e))},cancel:e=>{t.forEach(t=>t.cancel(e))},each:s,onComplete:o,timeout:()=>{}};return i.timeout=y(!0,i),i}(e):h()}function h(){let e,t;const n=new Promise((n,o)=>{e=n,t=o}),o={promise:n,promises:null,done:e,cancel:t,each:()=>{},onComplete:g(n),timeout:()=>{}};return o.timeout=y(!1,o),o.each=(n,...r)=>{n({value:null,done:e,cancel:t,timeout:o.timeout},...r)},o}function g(e){return function(t,n=null){null===n?e.then(e=>t(e)):e.then(e=>t(e),e=>n(e))}}function y(e,t){let n;return n=e?Promise.all(t.promises.map(e=>e.promise)):t.promise,function(e,o){let r,s=new Promise((t,s)=>{r=setTimeout(()=>{t(o),Promise.resolve(n)},e)});return n.then(()=>clearTimeout(r)),t.onComplete=g(Promise.race([n,s])),t}}function v({message:e,level:t,type:n,logLevel:o}){if(0===o)return null;if(o<t)return null;const r=`[Debug]: ${e}`;switch(n){case"warn":console.warn(r);break;case"error":console.error(r);break;default:console.log(r)}return r}function x(e={},t=v){return function({message:n,type:o,level:r,...s}){const{level:i,type:c,defaultMessageLevel:u}=Object.assign({},{level:1e3,type:"log",defaultMessageLevel:1},e);return o||(o=c),r||(r=u),t({message:n,type:o,level:r,logLevel:i,...s})}}function*k(e,t,n,o){let r=null;if(null===e)return yield*o.map(e=>[e,"show"]),void(yield[n,"show"]);if(!o||0===o.length)return t?(yield[e,"hide"],t.reverse(),yield*t.map(e=>[e,"hide"]),void(yield[n,"show"])):(yield[e,"hide"],void(yield[n,"show"]));if(o.includes(e)){for(let t=o.indexOf(e)+1;t<o.length;t++)yield[o[t],"show"];return void(yield[n,"show"])}if(!t)return yield[e,"hide"],void(yield*o.map(e=>[e,"show"]));if(o.every((e,n)=>t[n]===o[n]&&(r=n,!0)),null==r)return yield[e,"hide"],t.reverse(),yield*t.map(e=>[e,"hide"]),yield*o.map(e=>[e,"show"]),void(yield[n,"show"]);yield[e,"hide"];for(let e=t.length;e>r+1;e--)yield[t[e-1],"hide"];for(let e=r+1;e<o.length;e++)yield[o[e],"show"];yield[n,"show"]}function C(e){return function(t,...n){const{askForPromise:o,deps:r}=e;return function(){const e=o();return t({task:e,dependencies:r()},...n),e.promise}}}return d.sequence=function(e,...t){const n=d(),o=[];const r=function*(e){for(const t of e)yield t}(e);return function e(t,...s){t.done?n.done(o):t.value(...s).then(t=>{o.push(t),e(r.next(),...s,t)})}(r.next(),...t),n},d.all=function(e,...t){const n=d(),o=[],r=e.map((e,n)=>"function"==typeof e?e(...t).then(e=>o[n]=e):e.then(e=>o[n]=e));return Promise.all(r).then(()=>n.done(o)),n},function(e={logLevel:0}){const t=p({errorEventName:"@app-error"}),n=x({level:e.logLevel||0}),o={currentScene:null,currentParents:null,sceneNames:new Set,scenes:{},opened:!1,jumpStack:[]},r={},s={shortcutMngr:t,findInstructions:k,askForPromise:d,setInstruction:C({askForPromise:d,deps:t.getDependencies}),log:n};return r.hide=function(e,t){return function(n=1){const{askForPromise:o,shortcutMngr:r,setInstruction:s}=e,{currentScene:i,currentParents:c,scenes:u}=t,l=o(),a=[],f=c.length>0;let p;return r.pause(),a.push(s(u[i].hide)),f||(t.currentScene=null),f&&"*"===n&&[...c].reverse().forEach(e=>{p=t.currentParents.pop(),t.currentScene=p,a.push(s(u[e].hide))}),f&&!["*",1].includes(n)&&c.slice("-"+(n-1)).reverse().map(e=>{p=t.currentParents.pop(),t.currentScene=p,a.push(s(u[e].hide))}),(n=o.sequence(a)).onComplete(()=>{r.changeContext(t.currentScene),l.done()}),l.promise}}(s,o),r.listShortcuts=function(e,t){return function(e){const{scenes:n,sceneNames:o}=t;if(!o.has(e))return null;const{show:r,hide:s,parents:i,beforeUnload:c,afterLoad:u,...l}=n[e];return Object.keys(l)}}(0,o),r.setScenes=function(e,t){return function(n){const{shortcutMngr:o}=e;n.forEach(e=>{if(null==e)return;const{name:n,scene:r}=e;if(null==r)return void console.warn(`Scene ${n} is not defined`);r.parents||(r.parents=[]),t.scenes[n]=r,t.sceneNames.add(n);const{show:s,hide:i,parents:c,...u}=r,l={};l[n]=u,o.load(l)})}}(s,o),r.show=function(e,t){return function({scene:n,options:o={ssr:!1}},...r){const{shortcutMngr:s,askForPromise:i,log:c,findInstructions:u,setInstruction:l}=e,a=i(),f=i(),{opened:p,scenes:m,sceneNames:d,currentPage:h}=t;if(h){const e=m[h].beforeHide;"function"==typeof e&&e({done:f.done,dependencies:s.getDependencies()})}else f.done(!0);return f.onComplete(e=>{if(!e)return a.done(),a.promise;if(!d.has(n)&&c)return c({message:`Scene ${n} is not available.`,level:1,type:"error"}),a.done(),a.promise;if(!p&&o.ssr)return t.opened=!0,t.currentPage=n,s.changeContext(n),a.done(),a.promise;const{show:f,parents:h=[]}=m[n];if("*"===h[0])return f().then(()=>a.done()),t.currentParents.push(t.currentPage),t.currentPage=n,a.promise;function g([e,n]){if("show"===n)t.currentScene&&t.currentParents.push(t.currentScene),t.currentScene=e;else{let e=t.currentParents.pop();t.currentScene=e}return m[e][n]}h.forEach(e=>d.has(e)),t.currentParents||(t.currentParents=[]);const y=u(t.currentScene,t.currentParents,n,h),v=[];for(let e of y)[e].map(g).map(e=>v.push(l(e),...r));i.sequence(v).onComplete(()=>{t.opened=!0,s.changeContext(n),"function"==typeof m[n].afterShow&&m[n].afterShow({dependencies:s.getDependencies(),done:()=>{}}),a.done()})}),a.promise}}(s,o),r.jump=function(e,t){return function({scene:n},...o){return e.jumpStack.push(e.currentScene),t({scene:n},...o)}}(o,r.show),r.jumpBack=function(e,t){return function({hops:n}={hops:1},...o){for(let t=0;t<n-1;t++)e.jumpStack.pop();if(0===e.jumpStack.length)return;const r=e.jumpStack.pop();return t({scene:r},...o)}}(o,r.show),r.jumpsReset=function(e){return function(){e.jumpStack=[]}}(o),r.loadPlugins=async function(e){const t=e.map(e=>`plugin${e}`),n=await Promise.resolve().then(function(){return m});return t.map(e=>n[e])},r.setDependencies=e=>t.setDependencies(e),r.getDependencies=()=>t.getDependencies(),r.setNote=e=>p.setNote(e),r.listScenes=()=>[...o.sceneNames],r.enablePlugin=(e,n)=>t.enablePlugin(e,n),r.disablePlugin=e=>t.disablePlugin(e),r.emit=(e,...n)=>t.emit(e,...n),r}});
1
+ !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).cuts=t()}(this,function(){"use strict";var e={_normalizeWithPlugins:function(e,t){return function(e){const n=t.shortcuts;Object.keys(n).forEach(t=>{Object.entries(n[t]).forEach(([r,o])=>{const s=e(r);s!==r&&(delete n[t][r],n[t][s]=o)})})}},_readShortcutWithPlugins:function(e,t){return function(n){const{inAPI:r}=e,o=n.split(":")[0].toLowerCase().trim(),s=r._systemAction(o,"none");let i=n;return-1!==s&&(i=t.plugins[s].shortcutName(n)),i}},_systemAction:function(e,t){return function(e,n,r=null){return t.plugins.findIndex(t=>t.getPrefix()===e&&(t[n]&&t[n](r),!0))}},changeContext:function(e,t){const{shortcuts:n,currentContext:r,ERROR_EVENT_NAME:o}=t,{ev:s}=e;return function(e=!1){const i=r.name;if(!e)return s.reset(),void(r.name=null);i!==e&&(n[e]?(n[i]&&s.reset(),r.name=e,t.plugins.forEach(t=>t.contextChange(e)),Object.entries(n[e]).forEach(([e,t])=>{t.forEach(t=>s.on(e,t))}),s.on("*",(...e)=>{t.exposeShortcut&&t.exposeShortcut(...e)})):s.emit(o,`Context '${e}' does not exist`))}},listShortcuts:function(e,t){const n=t.shortcuts;return function(e=null){if(null!=e){let t=n[e];return null==t?null:Object.entries(t).map(([e,t])=>e)}return Object.keys(n).map(e=>{let t={};return t.context=e,t.shortcuts=Object.entries(n[e]).map(([e,t])=>e),t})}},load:function(e,t){const{shortcuts:n,plugins:r}=t,{API:{changeContext:o,getContext:s}}=e;return function(e){const t=s(),i=r.map(e=>e.getPrefix().toUpperCase());let c=!1;Object.entries(e).forEach(([e,o])=>{e===t&&(c=!0),n[e]={},Object.entries(o).forEach(([t,o])=>{let s=t,c=t.toUpperCase().trim(),u=i.map((e,t)=>c.startsWith(e)?t:null).filter(e=>null!==e);if(u.length){let e=u[0];s=r[e].shortcutName(t)}o instanceof Function&&(o=[o]),n[e][s]=o})}),c&&(o(),o(t))}},unload:function(e,t){const{currentContext:n,shortcuts:r,ERROR_EVENT_NAME:o}=t,{ev:s}=e;return function(e){n.name!==e?r[e]?delete r[e]:s.emit(o,`Context '${e}' does not exist`):s.emit(o,`Context '${e}' can't be removed during is current active context. Change the context first`)}}};function t(e){const t=e.toUpperCase(),n=/KEY\s*\:/i.test(t),r=t.indexOf(":");return n?`KEY:${t.slice(r+1).split(",").map(e=>e.trim()).map(e=>e.split("+").map(e=>e.trim()).sort().join("+")).join(",")}`:e}function n(e,t){let{shiftKey:n,altKey:r,ctrlKey:o}=e,s=t(),i=e.code.replace("Key","").replace("Digit",""),c=[];return o&&c.push("CTRL"),n&&c.push("SHIFT"),r&&c.push("ALT"),s.hasOwnProperty(i)?c.push(s[i].toUpperCase()):["ControlLeft","ControlRight","ShiftLeft","ShiftRight","AltLeft","AltRight","Meta"].includes(i)||c.push(i.toUpperCase()),c.sort()}function r(e,t){let n=0;const{regex:r}=e,{listenOptions:o,currentContext:{name:s},shortcuts:i}=t;return null==s?0:(Object.entries(i[s]).forEach(([e,t])=>{if(!r.test(e))return;n++;let s=e.slice(4).split(",").length;o.maxSequence<s&&(o.maxSequence=s)}),n)}function o(){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(e,t,n){const{listenOptions:{clickTarget:r}}=t;let o=n;return o===document||o===document.body?null:o.dataset[r]||"A"===o.nodeName?o:s(e,t,o.parentNode)}function i(e){const t=e.toUpperCase(),n=/CLICK\s*\:/i.test(t),r=["LEFT","MIDDLE","RIGHT"],o=["ALT","SHIFT","CTRL"];let s=null,i=[],c=0,u=t.indexOf(":");return n?(t.slice(u+1).trim().split("-").map(e=>e.trim()).forEach(e=>{r.includes(e)?s=e:o.includes(e)?i.push(e):isNaN(e)||(c=e)}),`CLICK:${s}-${c}${i.length>0?"-":""}${i.sort().join("-")}`):e}function c(e,t){let{shiftKey:n,altKey:r,ctrlKey:o,key:s,button:i}=e,c=`CLICK:${["LEFT","MIDDLE","RIGHT"][i]}-${t}`,u=[];return o&&u.push("CTRL"),n&&u.push("SHIFT"),r&&u.push("ALT"),u.length>0?`${c}${u.length>0?"-":""}${u.sort().join("-")}`:`${c}`}function u(e,t){let n=0;const{regex:r}=e,{listenOptions:o,currentContext:{name:s},shortcuts:i}=t;return null==s?0:(Object.entries(i[s]).forEach(([e,t])=>{if(!r.test(e))return;n++;let[,s]=e.slice(6).split("-");o.maxClicks<s&&(o.maxClicks=s)}),n)}function l(e){const t=e.toUpperCase(),n=/FORM\s*\:/i.test(t),r=t.indexOf(":");return n?`FORM:${t.slice(r+1).trim()}`:e}function a(e,t){const{regex:n,_defaults:r,ev:o}=e,{currentContext:{name:s},shortcuts:i,callbacks:c}=t;let u=[],l=[],a=[];if(null==s)return!1;if(Object.entries(i[s]).forEach(([e,t])=>{n.test(e)&&("FORM:WATCH"===e&&(u=t),"FORM:DEFINE"===e&&(l=t),"FORM:ACTION"===e&&(a=t))}),0===a.length)return!1;let f=new Set;0===l.length&&(l=[r.define]),0===u.length&&(u=[r.watch]);let p=u.map(e=>e()).reduce((e,t)=>(e.push(t),e),[]);return t.watchList=document.querySelectorAll(p),t.watchList.forEach(e=>f.add(l[0](e))),t.typeFn=l[0]?l[0]:r.define,a.forEach(n=>{if(!(n instanceof Function))return console.warn("Warning: The 'form:action' should be a function."),!1;let r=n({dependencies:e.mainDependencies.extra});if(!(r instanceof Array))return console.warn("Warning: The 'form:action' function should RETURN an array."),!1;r.forEach(({fn:e,type:n,timing:r,wait:s=0})=>{if(f.has(n)&&e instanceof Function){let t=`${n}/${r}`;const s=c.hasOwnProperty(t);s?c[t].push(e):c[t]=[e],s||o.on(t,(e,t)=>{t.forEach(t=>{t instanceof Function&&t(e)})})}"instant"===r&&(t.wait[`${n}`]=s)})}),Object.keys(t.callbacks).length>0}const f={watch:()=>"input, select, textarea, button, a",define:e=>"checkbox"===e.type||"radio"===e.type?"checkbox":"button"==e.type||"submit"==e.type?"button":"input"};function p(t={}){let n={},r={};const o=function(){let e={"*":[]},t={},n=new Set,r=!1,o="";return{on:function(t,n){e[t]||(e[t]=[]),e[t].push(n)},once:function(e,n){"*"!==e&&(t[e]||(t[e]=[]),t[e].push(n))},off:function(n,r){if(r)return e[n]&&(e[n]=e[n].filter(e=>e!==r)),t[n]&&(t[n]=t[n].filter(e=>e!==r)),e[n]&&0===e[n].length&&delete e[n],void(t[n]&&0===t[n].length&&delete e[n]);t[n]&&delete t[n],e[n]&&delete e[n]},reset:function(){e={"*":[]},t={},n=new Set},emit:function(){const[s,...i]=arguments;function c(t){let r=!1;"*"!==t&&(n.has(t)||(e[t].every(e=>{const t=e(...i);return"string"!=typeof t||"STOP"!==t.toUpperCase()||(r=!0,!1)}),r||e["*"].forEach(e=>e(s,...i))))}if(r&&(console.log(`${o} Event "${s}" was triggered.`),i.length>0&&(console.log("Arguments:"),console.log(...i),console.log("^----"))),"*"!==s){if(t[s]){if(n.has(s))return;t[s].forEach(e=>e(...i)),delete t[s]}e[s]&&c(s)}else Object.keys(e).forEach(e=>c(e))},stop:function(r){if("*"===r){const r=Object.keys(e),o=Object.keys(t);return void(n=new Set([...o,...r]))}n.add(r)},start:function(e){"*"!==e?n.delete(e):n.clear()},debug:function(e,t){r=!!e,t&&"string"==typeof t&&(o=t)}}}(),s={currentContext:{name:null,note:null},shortcuts:{},plugins:[],exposeShortcut:!(!t.onShortcut||"function"!=typeof t.onShortcut)&&t.onShortcut,ERROR_EVENT_NAME:t.errorEventName?t.errorEventName:"@shortcuts-error"};let i={ev:o,inAPI:n,API:r,extra:{}};return r.enablePlugin=(e,t={})=>{if("function"!=typeof e)return;let r=e(i,s,t);const o=r.getPrefix();-1===n._systemAction(o,"none")?s.plugins.push(r):r.destroy()},r.disablePlugin=e=>{const t=n._systemAction(e,"destroy");-1!==t&&(s.plugins=s.plugins.filter((e,n)=>n!==t))},r.mutePlugin=e=>n._systemAction(e,"mute"),r.unmutePlugin=e=>n._systemAction(e,"unmute"),r.listPlugins=()=>s.plugins.map(e=>e.getPrefix()),r.getContext=()=>s.currentContext.name,r.getNote=()=>s.currentContext.note,r.setNote=(e=null)=>{"string"!=typeof e&&null!=e||(s.currentContext.note=e)},r.pause=(e="*")=>{let t=n._readShortcutWithPlugins(e);o.stop(t)},r.resume=(e="*")=>{const t=n._readShortcutWithPlugins(e);o.start(t)},r.emit=(e,...t)=>o.emit(n._readShortcutWithPlugins(e),...t),r.listContexts=()=>Object.keys(s.shortcuts),r.setDependencies=e=>i.extra={...i.extra,...e},r.getDependencies=()=>i.extra,r.reset=function(){o.reset(),r.changeContext(),s.plugins.forEach(e=>e.destroy()),r.listContexts().map(e=>r.unload(e)),i.extra={},s.exposeShortcut=null},Object.entries(e).forEach(([e,t])=>{e.startsWith("_")?n[e]=t(i,s):r[e]=t(i,s)}),r}var m=Object.freeze({__proto__:null,pluginClick:function(e,t,n){let{currentContext:r,shortcuts:o}=t,{inAPI:l}=e,a={ev:e.ev,_findTarget:s,_readClickEvent:c,mainDependencies:e,regex:/CLICK\s*\:/i},f={currentContext:r,active:!1,shortcuts:o,listenOptions:{mouseWait:n.mouseWait?n.mouseWait:320,maxClicks:1,clickTarget:n.clickTarget?n.clickTarget:"click"}};l._normalizeWithPlugins(i);let p=function(e,t){const{ev:n,_findTarget:r,_readClickEvent:o,mainDependencies:s}=e,{listenOptions:i,currentContext:c}=t,{mouseWait:u}=i;let l=null,a=null,f=null,p=null,m=0;function d(){const e=o(a,m),t={target:l,targetProps:l?l.getBoundingClientRect():null,x:a.clientX,y:a.clientY,context:c.name,note:c.note,event:a,dependencies:s.extra,type:"click"};n.emit(e,t),f=null,p=null,l=null,a=null,m=0}function h(n){let o=i.maxClicks;return clearTimeout(f),p?(clearTimeout(p),void(p=setTimeout(()=>p=null,u))):(l=r(e,t,n.target),l&&l.dataset.hasOwnProperty("quickClick")&&(o=1),l&&"A"===l.tagName&&(o=1),a=n,m++,m>=o?(d(),void(o>1&&(p=setTimeout(()=>p=null,u)))):void(f=setTimeout(d,u)))}function g(n){let o=i.maxClicks;return clearTimeout(f),p?(clearTimeout(p),void(p=setTimeout(()=>p=null,u))):(l=r(e,t,n.target),l&&l.dataset.hasOwnProperty("quickClick")&&(o=1),l&&"A"===l.tagName&&(o=1),a=n,m++,m>=o?(d(),void(o>1&&(p=setTimeout(()=>p=null,u)))):void(f=setTimeout(d,u)))}return{start:function(){t.active||(window.addEventListener("contextmenu",g),document.addEventListener("click",h),t.active=!0)},stop:function(){t.active&&(window.removeEventListener("contextmenu",g),document.removeEventListener("click",h),t.active=!1,f&&(clearTimeout(f),f=null),p&&(clearTimeout(p),p=null),m=0)}}}(a,f),m=u(a,f);m>0&&p.start();let d={getPrefix:()=>"click",shortcutName:e=>i(e),contextChange:()=>{m=u(a,f),m<1&&p.stop(),m>0&&p.start()},mute:()=>{p.stop()},unmute:()=>p.start(),destroy:()=>p.stop()};return Object.freeze(d),d},pluginForm:function(e,t,n){let{currentContext:r,shortcuts:o}=t,{inAPI:s}=e,i={ev:e.ev,mainDependencies:e,regex:/FORM\s*\:/i,_defaults:f},c={currentContext:r,shortcuts:o,callbacks:{},typeFn:"",watchList:[],wait:{}};s._normalizeWithPlugins(l);let u=function(e,t){const{ev:n}=e;let r=null;function o(e,t,n,r){return{target:n.target,context:t.currentContext.name,note:t.currentContext.note,event:n,dependencies:e.mainDependencies.extra,type:r}}function s(r){const{callbacks:s,typeFn:i}=t,c=i(r.target),u=o(e,t,r,c),l=`${c}/in`;null!=s[l]&&n.emit(l,u,s[l])}function i(r){const{callbacks:s,typeFn:i}=t,c=o(e,t,r,"form-out"),u=`${i(r.target)}/out`;null!=s[u]&&n.emit(u,c,s[u])}function c(s){const{callbacks:i,typeFn:c}=t,u=o(e,t,s,"form-instant"),l=c(s.target),a=t.wait[`${l}`],f=`${l}/instant`;null!=i[f]&&(0!==a?(clearTimeout(r),r=setTimeout(()=>n.emit(f,u,i[f]),a)):n.emit(f,u,i[f]))}return{start:function(){t.active||(document.addEventListener("focusin",s),document.addEventListener("focusout",i),document.addEventListener("input",c),t.active=!0)},stop:function(){t.active&&(document.removeEventListener("focusin",s),document.removeEventListener("focusout",i),document.removeEventListener("input",c),t.active=!1)}}}(i,c);r.name&&a(i,c)&&u.start();let p={getPrefix:()=>"form",shortcutName:e=>l(e),contextChange:()=>{c.callbacks={},c.typeFn="",c.watchList=[],c.wait={},a(i,c)?u.start():u.stop()},mute:()=>u.stop(),unmute:()=>u.start(),destroy:()=>{u.stop()}};return Object.freeze(p),p},pluginKey:function(e,s,i={}){let{currentContext:c,shortcuts:u,exposeShortcut:l}=s,{inAPI:a}=e,f={ev:e.ev,_specialChars:o,_readKeyEvent:n,mainDependencies:e,regex:/KEY\s*\:/i},p={currentContext:c,shortcuts:u,active:!1,listenOptions:{keyWait:i.keyWait?i.keyWait:480,maxSequence:1,keyIgnore:null},streamKeys:!(!i.streamKeys||"function"!=typeof i.streamKeys)&&i.streamKeys};a._normalizeWithPlugins(t);let m=function(e,t){const{ev:n,_specialChars:r,_readKeyEvent:o,mainDependencies:s}=e,{currentContext:i,streamKeys:c,listenOptions:u}=t,{keyWait:l}=u;let a=[],f=null,p=!0,m=!1;const d=()=>p=!1,h=()=>p=!0,g=()=>m=!0,y=()=>!1===p;function v(){let e=a.map(e=>[e.join("+")]);const t={wait:d,end:h,ignore:g,isWaiting:y,note:i.note,context:i.name,dependencies:s.extra,type:"key"};if(!p){let r=e.at(-1);n.emit(r,t),m&&(e=e.slice(0,-1),m=!1)}if(p){const r=`KEY:${e.join(",")}`;n.emit(r,t),a=[],f=null}}function x(t){if(clearTimeout(f),r().hasOwnProperty(t.code))return a.push(o(t,r)),c&&c({key:t.key,context:i.name,note:i.note,dependencies:e.extra}),u.keyIgnore?(clearTimeout(u.keyIgnore),void(u.keyIgnore=setTimeout(()=>u.keyIgnore=null,l))):p&&a.length===u.maxSequence?(v(),void(u.keyIgnore=setTimeout(()=>u.keyIgnore=null,l))):void(p?f=setTimeout(v,l):v())}function k(t){if(!r().hasOwnProperty(t.code)){if(clearTimeout(f),c&&c({key:t.key,context:i.name,note:i.note,dependencies:e.extra}),u.keyIgnore)return clearTimeout(u.keyIgnore),void(u.keyIgnore=setTimeout(()=>u.keyIgnore=null,l));if(a.push(o(t,r)),p&&a.length===u.maxSequence)return v(),void(u.keyIgnore=setTimeout(()=>u.keyIgnore=null,l));p?f=setTimeout(v,l):v()}}return{start:function(){t.active||(document.addEventListener("keydown",x),document.addEventListener("keypress",k),t.active=!0)},stop:function(){t.active&&(document.removeEventListener("keydown",x),document.removeEventListener("keypress",k),t.active=!1,f&&(clearTimeout(f),f=null),u.keyIgnore&&(clearTimeout(u.keyIgnore),u.keyIgnore=null),a=[],p=!0,m=!1)}}}(f,p),d=r(f,p);d>0&&m.start();let h={getPrefix:()=>"key",shortcutName:e=>t(e),contextChange:e=>{d=r(f,p),d<1&&m.stop(),d>0&&m.start()},mute:()=>m.stop(),unmute:()=>m.start(),destroy:()=>m.stop()};return Object.freeze(h),h},shortcuts:p});function d(e){return e?function(e){let t=e.map(e=>h()),n=t.map(e=>e.promise);t.promises=t;let r=g(Promise.all(n));function o(e){let t="pending";return e.then(()=>t="fulfilled").catch(()=>t="rejected"),t}function s(n,...r){t.forEach((t,s)=>n({value:e[s],done:t.done,cancel:t.cancel,timeout:t.timeout,state:o(t.promise)},...r))}const i={promise:Promise.all(n),promises:t,done:e=>{t.forEach(t=>t.done(e))},cancel:e=>{t.forEach(t=>t.cancel(e))},each:s,onComplete:r,timeout:()=>{}};return i.timeout=y(!0,i),i}(e):h()}function h(){let e,t;const n=new Promise((n,r)=>{e=n,t=r}),r={promise:n,promises:null,done:e,cancel:t,each:()=>{},onComplete:g(n),timeout:()=>{}};return r.timeout=y(!1,r),r.each=(n,...o)=>{n({value:null,done:e,cancel:t,timeout:r.timeout},...o)},r}function g(e){return function(t,n=null){null===n?e.then(e=>t(e)):e.then(e=>t(e),e=>n(e))}}function y(e,t){let n;return n=e?Promise.all(t.promises.map(e=>e.promise)):t.promise,function(e,r){let o,s=new Promise((t,s)=>{o=setTimeout(()=>{t(r),Promise.resolve(n)},e)});return n.then(()=>clearTimeout(o)),t.onComplete=g(Promise.race([n,s])),t}}function v({message:e,level:t,type:n,logLevel:r}){if(0===r)return null;if(r<t)return null;const o=`[Debug]: ${e}`;switch(n){case"warn":console.warn(o);break;case"error":console.error(o);break;default:console.log(o)}return o}function x(e={},t=v){return function({message:n,type:r,level:o,...s}){const{level:i,type:c,defaultMessageLevel:u}=Object.assign({},{level:1e3,type:"log",defaultMessageLevel:1},e);return r||(r=c),o||(o=u),t({message:n,type:r,level:o,logLevel:i,...s})}}function*k(e,t,n,r){let o=null,s=!0;if(null===e)return yield*r.map(e=>[e,"show"]),void(yield[n,"show"]);if(0!==r.length){if(r.includes(e)){for(let t=r.indexOf(e)+1;t<r.length;t++)yield[r[t],"show"];return void(yield[n,"show"])}if(!t)return yield[e,"hide"],void(yield*r.map(e=>[e,"show"]));if(r.every((e,n)=>t[n]===r[n]&&(o=n,!0)),null==o)return yield[e,"hide"],t.reverse(),yield*t.map(e=>[e,"hide"]),yield*r.map(e=>[e,"show"]),void(yield[n,"show"]);yield[e,"hide"];for(let e=t.length;e>o+1;e--)yield[t[e-1],"hide"];for(let e=o+1;e<r.length;e++)yield[r[e],"show"];yield[n,"show"]}else{if(yield[e,"hide"],t.includes(n)){let e=t.indexOf(n),r=t.filter((t,n)=>n>e);r.reverse(),yield*r.map(e=>[e,"hide"]),s=!1}else{let e=[...t];e.reverse(),yield*e.map(e=>[e,"hide"])}s&&(yield[n,"show"])}}function C(e){return function(t,...n){const{askForPromise:r,deps:o}=e;return function(){const e=r();return t({task:e,dependencies:o()},...n),e.promise}}}return d.sequence=function(e,...t){const n=d(),r=[];const o=function*(e){for(const t of e)yield t}(e);return function e(t,...s){t.done?n.done(r):t.value(...s).then(t=>{r.push(t),e(o.next(),...s,t)})}(o.next(),...t),n},d.all=function(e,...t){const n=d(),r=[],o=e.map((e,n)=>"function"==typeof e?e(...t).then(e=>r[n]=e):e.then(e=>r[n]=e));return Promise.all(o).then(()=>n.done(r)),n},function(e={logLevel:0}){const t=p({errorEventName:"@app-error"}),n=x({level:e.logLevel||1},e=>{const{type:n}=e;"error"===n&&t.emit("@app-error",e)}),r={currentScene:null,currentParents:null,sceneNames:new Set,scenes:{},opened:!1,jumpStack:[]},o={},s={shortcutMngr:t,findInstructions:k,askForPromise:d,setInstruction:C({askForPromise:d,deps:t.getDependencies}),log:n};return o.hide=function(e,t){return function(n=1){const{askForPromise:r,shortcutMngr:o,setInstruction:s}=e,{currentScene:i,currentParents:c,scenes:u}=t,l=r(),a=[],f=c.length>0;let p;return o.pause(),a.push(s(u[i].hide)),f||(t.currentScene=null),f&&"*"===n&&[...c].reverse().forEach(e=>{p=t.currentParents.at(-1),t.currentScene=p,a.push(s(u[e].hide))}),f&&!["*",1].includes(n)&&c.slice("-"+(n-1)).reverse().map(e=>{p=t.currentParents.at(-1),t.currentScene=p,a.push(s(u[e].hide))}),(n=r.sequence(a)).onComplete(()=>{o.changeContext(t.currentScene),l.done()}),l.promise}}(s,r),o.listShortcuts=function(e,t){return function(e){const{scenes:n,sceneNames:r}=t;if(!r.has(e))return null;const{show:o,hide:s,parents:i,beforeUnload:c,afterLoad:u,...l}=n[e];return Object.keys(l)}}(0,r),o.setScenes=function(e,t){return function(n){const{shortcutMngr:r,log:o}=e;n.forEach(e=>{if(null==e)return;const{name:n,scene:s}=e;if(!n)return void o({message:"Scene name is not defined",level:1,type:"error"});if(null==s)return void o({message:`Scene ${n} is not defined`,level:1,type:"error"});s.parents||(s.parents=[]),t.scenes[n]=s,t.sceneNames.add(n);const{show:i,hide:c,parents:u,...l}=s,a={};a[n]=l,r.load(a)})}}(s,r),o.show=function(e,t){return function({scene:n,options:r={ssr:!1}},...o){const{shortcutMngr:s,askForPromise:i,log:c,findInstructions:u,setInstruction:l}=e,a=i(),f=i(),{opened:p,scenes:m,sceneNames:d,currentScene:h}=t;return h&&"function"==typeof m[h].beforeHide?(0,m[h].beforeHide)({done:f.done,dependencies:s.getDependencies()}):f.done(!0),f.onComplete(e=>{if(!e)return a.done(),a.promise;if(!d.has(n))return c({message:`Scene "${n}" is not available.`,level:1,type:"error"}),a.done(),a.promise;if(!p&&r.ssr)return t.opened=!0,t.currentScene=n,s.changeContext(n),a.done(),a.promise;const{show:f,parents:h=[]}=m[n];if("*"===h[0])return l(f,...o)().then(()=>a.done()),t.currentParents.push(t.currentScene),t.currentScene=n,a.promise;if(0!==h.length&&!h.every(e=>d.has(e)))return c({message:`Some of '${n}' parent scenes are not set.`,level:1,type:"error"}),a.done(),a.promise;function g([e,n]){if("show"===n)t.currentScene&&(t.currentParents=[...m[t.currentScene].parents]),t.currentScene=e;else{let n=m[e].parents.at(-1);t.currentScene=n}return m[e][n]}t.currentParents||(t.currentParents=[]);const y=u(t.currentScene,t.currentParents,n,h),v=[];for(let e of y){const t=g(e);v.push(l(t,...o))}i.sequence(v).onComplete(()=>{t.opened=!0,t.currentScene=n,t.currentParents=m[n].parents||null,s.changeContext(n),"function"==typeof m[n].afterShow&&m[n].afterShow({dependencies:s.getDependencies(),done:()=>{}}),a.done()})}),a.promise}}(s,r),o.jump=function(e,t){return function({scene:n},...r){return e.jumpStack.push(e.currentScene),t({scene:n},...r)}}(r,o.show),o.jumpBack=function(e,t){return function({hops:n}={hops:1},...r){for(let t=0;t<n-1;t++)e.jumpStack.pop();if(0===e.jumpStack.length)return;const o=e.jumpStack.pop();return t({scene:o},...r)}}(r,o.show),o.jumpsReset=function(e){return function(){e.jumpStack=[]}}(r),o.loadPlugins=async function(e){const t=e.map(e=>`plugin${e}`),n=await Promise.resolve().then(function(){return m});return t.map(e=>n[e])},o.setDependencies=e=>t.setDependencies(e),o.getDependencies=()=>t.getDependencies(),o.setNote=e=>p.setNote(e),o.listScenes=()=>[...r.sceneNames],o.enablePlugin=(e,n)=>t.enablePlugin(e,n),o.disablePlugin=e=>t.disablePlugin(e),o.getState=()=>({scene:r.currentScene,parents:r.currentParents,opened:r.opened}),o.emit=(e,...n)=>t.emit(e,...n),o}});
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@peter.naydenov/cuts",
3
3
  "description": "SPA scene manager",
4
- "version": "1.4.5",
4
+ "version": "1.6.0",
5
5
  "license": "MIT",
6
6
  "author": "Peter Naydenov",
7
7
  "main": "./src/main.js",
@@ -35,14 +35,14 @@
35
35
  "@rollup/plugin-commonjs": "^28.0.8",
36
36
  "@rollup/plugin-node-resolve": "^16.0.3",
37
37
  "@rollup/plugin-terser": "^0.4.4",
38
- "@types/node": "^24.9.0",
38
+ "@types/node": "^24.9.1",
39
39
  "@vitejs/plugin-vue": "^6.0.1",
40
- "@vitest/coverage-v8": "^3.2.4",
40
+ "@vitest/coverage-v8": "^4.0.1",
41
41
  "cypress": "^15.5.0",
42
42
  "rollup": "^4.52.5",
43
43
  "typescript": "^5.9.3",
44
44
  "vite": "^7.1.11",
45
- "vitest": "^3.2.4",
45
+ "vitest": "^4.0.1",
46
46
  "vue": "^3.5.22"
47
47
  },
48
48
  "dependencies": {
@@ -5,34 +5,38 @@
5
5
  * @function findInstructions
6
6
  * @description Generator that yields instructions for transitioning between scenes
7
7
  * @param {string|null} currentName - current scene name
8
- * @param {Array.<string>|null} currentParents - current scene parents
8
+ * @param {Array.<string>} currentParents - current scene parents
9
9
  * @param {string} targetName - target scene name
10
10
  * @param {Array.<string>} targetParents - target scene parents
11
11
  * @yields {Array.<string, 'show'|'hide'>} - instruction array with scene name and action
12
12
  */
13
13
  function* findInstructions ( currentName, currentParents, targetName, targetParents ) {
14
- let backToName, backIndex=null;
15
-
14
+ let backToName, backIndex=null, isNoParent=true;
15
+
16
16
  if ( currentName === null ) { // When the scene manager is just started
17
17
  yield* targetParents.map ( name => [ name, 'show' ])
18
18
  yield [ targetName, 'show' ]
19
19
  return
20
20
  }
21
21
 
22
- if ( !targetParents || targetParents.length === 0 ) { // Need to close all current parents, then open the target
23
- if ( !currentParents ) {
24
- yield [ currentName, 'hide' ]
25
- yield [ targetName, 'show' ]
26
- return
27
- }
22
+ if ( targetParents.length === 0 ) { // Need to close all current parents, then open the target
28
23
  yield [ currentName, 'hide' ]
29
- currentParents.reverse ()
30
- yield* currentParents.map ( name => [ name, 'hide' ])
31
- yield [ targetName, 'show' ]
24
+ if ( currentParents.includes ( targetName ) ) {
25
+ let index = currentParents.indexOf ( targetName );
26
+ let filtered = currentParents.filter ( (x,i) => i > index )
27
+ filtered.reverse ()
28
+ yield* filtered.map ( name => [ name, 'hide' ])
29
+ isNoParent = false
30
+ } else {
31
+ let cp = [...currentParents]
32
+ cp.reverse ()
33
+ yield* cp.map ( name => [ name, 'hide' ])
34
+ }
35
+ if ( isNoParent ) yield [ targetName, 'show' ]
32
36
  return
33
37
  }
34
38
 
35
- if ( targetParents.includes ( currentName ) ) { // Target is a subpage of the current page. No closing needed.
39
+ if ( targetParents.includes ( currentName ) ) { // Target is a subscene of the current scene. No closing needed.
36
40
  let id = targetParents.indexOf ( currentName );
37
41
  for ( let i = id+1; i < targetParents.length; i++ ) {
38
42
  yield [ targetParents[i], 'show' ]
@@ -67,6 +71,7 @@ function* findInstructions ( currentName, currentParents, targetName, targetPare
67
71
  return
68
72
  }
69
73
 
74
+
70
75
  yield [ currentName, 'hide' ]
71
76
  for ( let i = currentParents.length; i > backIndex+1; i-- ) {
72
77
  yield [ currentParents[i-1], 'hide' ]
package/src/main.js CHANGED
@@ -37,8 +37,13 @@ import jumpsReset from './methods/jumpsReset.js'
37
37
  function main ( cfg= {logLevel:0} ) {
38
38
  const
39
39
  shortcutMngr = shortcuts ({ errorEventName: '@app-error' })
40
- , logLevel = cfg.logLevel || 0
41
- , log = createLog ({ level:logLevel })
40
+ , logLevel = cfg.logLevel || 1
41
+ , log = createLog ({ level:logLevel }, (arg) => {
42
+ const { type } = arg;
43
+ if ( type === 'error' ) {
44
+ shortcutMngr.emit ( '@app-error', arg )
45
+ }
46
+ })
42
47
  , state = {
43
48
  currentScene : null // Current scene name;
44
49
  , currentParents : null // Current scene parents if any;
@@ -134,6 +139,20 @@ function main ( cfg= {logLevel:0} ) {
134
139
  * @returns void
135
140
  */
136
141
  API.disablePlugin = ( pluginName ) => shortcutMngr.disablePlugin ( pluginName )
142
+
143
+ /**
144
+ * Get the current state of the application
145
+ * @function getState
146
+ * @returns {Object} with properties:
147
+ * - scene: current scene name
148
+ * - parents: current parent scene names
149
+ * - opened: boolean indicating if the application is opened
150
+ */
151
+ API.getState = () => ({
152
+ scene : state.currentScene
153
+ , parents : state.currentParents
154
+ , opened : state.opened
155
+ })
137
156
 
138
157
 
139
158
  /**
@@ -26,14 +26,14 @@ return function hide ( endSteps=1 ) {
26
26
 
27
27
  if ( hasParents && endSteps === '*' ) {
28
28
  [...currentParents].reverse().forEach ( name => {
29
- el = state.currentParents.pop ();
29
+ el = state.currentParents.at ( -1 )
30
30
  state.currentScene = el
31
31
  instructions.push ( setInstruction ( scenes[name].hide))
32
32
  })
33
33
  }
34
34
  if ( hasParents && ![ '*', 1].includes(endSteps) ) {
35
35
  currentParents.slice ( `-${endSteps-1}` ).reverse().map ( name => {
36
- el = state.currentParents.pop ();
36
+ el = state.currentParents.at ( -1 )
37
37
  state.currentScene = el
38
38
  instructions.push ( setInstruction (scenes[name].hide))
39
39
  })
@@ -1,11 +1,15 @@
1
1
  'use strict'
2
2
 
3
3
 
4
+ /**
5
+ * @typedef {Object} AskObject
6
+ * @property {function} done - Mark the task as done
7
+ */
4
8
  /**
5
9
  * @typedef {Object} SceneObject
6
- * @property {function} show - load interface and prerequisites for the scene;
10
+ * @property {function({task: AskObject, dependencies: *}): void} show - load interface and prerequisites for the scene;
7
11
  * @property {function():boolean} [afterShow] - run after scene is loaded. Optional. Returns true to continue loading, false to cancel;
8
- * @property {function():void} hide - Reverse the settings from 'show';
12
+ * @property {function({task: AskObject, dependencies: *}): void} hide - Reverse the settings from 'show';
9
13
  * @property {function():void} [beforeHide] - Run before scene is hidden. Optional;
10
14
  * @property {Array.<string>} [parents] - list of parent scene names.
11
15
  * @property {*} ... - shortcut descriptions
@@ -30,15 +34,27 @@ function setScenes ( dependencies, state ) {
30
34
  * @description Screen Description is an object with fields 'name' and 'scene'
31
35
  */
32
36
  return function setScenes ( list ) {
33
- const { shortcutMngr } = dependencies;
34
- list.forEach ( item => {
35
- if ( item == null ) return
36
- const {name, scene } = item;
37
- if ( scene == null ) {
38
- console.warn ( `Scene ${name} is not defined` )
39
- return
40
- }
41
- if ( !scene.parents ) scene.parents = []
37
+ const { shortcutMngr, log } = dependencies;
38
+ list.forEach ( item => {
39
+ if ( item == null ) return
40
+ const {name, scene } = item;
41
+ if ( !name ) {
42
+ log ({
43
+ message: `Scene name is not defined`
44
+ , level : 1
45
+ , type : 'error'
46
+ })
47
+ return
48
+ }
49
+ if ( scene == null ) {
50
+ log ({
51
+ message: `Scene ${name} is not defined`
52
+ , level : 1
53
+ , type : 'error'
54
+ })
55
+ return
56
+ }
57
+ if ( ! scene.parents ) scene.parents = []
42
58
  state.scenes[name] = scene
43
59
  state.sceneNames.add ( name )
44
60