@peter.naydenov/cuts 1.5.0 → 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,88 +1,126 @@
1
1
  # Release History
2
2
 
3
3
 
4
- ## 1.5.0 ( 2025-10-?? )
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
6
16
  - [x] Dev dependency update. Vitest - v.4.0.1
7
17
  - [x] Cuts has event '@app-error'. Shortcut errors will trigger this event;
8
18
  - [x] Type improvements;
9
19
  - [x] New method `getState` returns an object with the current state;
10
20
  - [x] Fix: Closing a long list of scenes breaks the state;
11
-
21
+ - [ ] Bug: SSR option for first scene loading;
12
22
 
13
23
 
14
24
 
15
25
  ## 1.4.4 ( 2025-10-10)
16
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;
17
29
 
18
30
 
19
31
 
20
32
  ## 1.4.3 ( 2025-09-30)
21
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;
22
36
 
23
37
 
24
38
 
25
39
  ## 1.4.2 ( 2025-09-29)
26
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
+
27
45
 
28
46
  ## 1.4.1. ( 2025-09-24)
29
47
  - [x] Fix: Cleaning a duplicated line of code in main.js;
30
-
48
+ - [ ] Bug: Closing a long list of scenes breaks the state;
49
+ - [ ] Bug: SSR option for first scene loading;
31
50
 
32
51
 
33
52
  ## 1.4.0 ( 2025-09-06)
34
53
  - [x] New methods: jump, jumpBack, jumpsReset;
35
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;
36
57
 
37
58
 
38
59
  ## 1.3.1 ( 2025-08-15)
39
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;
40
63
 
41
64
 
42
65
  ## 1.3.0 ( 2025-08-15)
43
66
  - [x] Dependency update. @peter.naydenov/shortcuts@3.1.5. Plugin 'form' is available;
44
67
  - [ ] Miss: Missing typedef for plugin 'form'
45
-
68
+ - [ ] Bug: Closing a long list of scenes breaks the state;
69
+ - [ ] Bug: SSR option for first scene loading;
46
70
 
47
71
 
48
72
  ## 1.2.8 ( 2025-05-03)
49
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
+
50
77
 
51
78
 
52
79
  ### 1.2.7 ( 2025-02-04)
53
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;
54
83
 
55
84
 
56
85
 
57
86
  ### 1.2.6 ( 2025-01-23)
58
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;
59
90
 
60
91
 
61
92
 
62
93
  ### 1.2.4 ( 2025-01-15)
63
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;
64
97
 
65
98
 
66
99
 
67
100
  ### 1.2.3 ( 2024-12-23)
68
101
  - [x] Dependency update. @peter.naydenov/shortcuts@3.1.2;
69
-
102
+ - [ ] Bug: Closing a long list of scenes breaks the state;
103
+ - [ ] Bug: SSR option for first scene loading;
70
104
 
71
105
 
72
106
  ### 1.2.2 ( 2024-12-22 )
73
107
  - [x] Fix: Wrong argument 'dependencies' for 'beforeHide' and 'afterShow' methods;
74
-
75
-
108
+ - [ ] Bug: Closing a long list of scenes breaks the state;
109
+ - [ ] Bug: SSR option for first scene loading;
76
110
 
77
111
  ### 1.2.1 ( 2024-12-21 )
78
112
  - [x] Fix: Wrong settings if missing 'beforeHide' method;
79
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;
80
116
 
81
117
 
82
118
  ### 1.2.0 (2024-12-21)
83
119
  - [x] Extend 'scene' with optional 'afterShow' and 'beforeHide' methods;
84
120
  - [ ] Bug: Wrong settings if missing 'beforeHide' method;
85
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;
86
124
 
87
125
 
88
126
 
@@ -90,16 +128,23 @@
90
128
  - [x] Type improvements;
91
129
  - [x] Refactoring related to types;
92
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;
93
134
 
94
135
 
95
136
 
96
137
  ### 1.0.2 (2024-12-12)
97
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;
98
141
 
99
142
 
100
143
 
101
144
  ### 1.0.1 (2024-05-10)
102
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;
103
148
 
104
149
 
105
150
 
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,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(!n)return yield[e,"hide"],void(yield[r,"show"]);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||0,u=r({level:i}),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}=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,l={};l[r]=u,t.load(l)})}}(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)&&i)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.currentPage=r,o.changeContext(r),d.done(),d.promise;const{show:a,parents:m=[]}=h[r];if("*"===m[0])return a().then(()=>d.done()),n.currentParents.push(n.currentPage),n.currentPage=r,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]}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){const n=g(e);S.push(l(n,...s))}c.sequence(S).onComplete(()=>{n.opened=!0,n.currentPage=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};
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,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(!n)return yield[e,"hide"],void(yield[r,"show"]);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||0,u=r({level:i}),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}=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,l={};l[r]=u,t.load(l)})}}(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:f,sceneNames:h,currentScene:m}=n;return m&&"function"==typeof f[m].beforeHide?(0,f[m].beforeHide)({done:a.done,dependencies:o.getDependencies()}):a.done(!0),a.onComplete(e=>{if(!e)return d.done(),d.promise;if(!h.has(r)&&i)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.currentPage=r,o.changeContext(r),d.done(),d.promise;const{show:a,parents:m=[]}=f[r];if("*"===m[0])return a().then(()=>d.done()),n.currentParents.push(n.currentPage),n.currentPage=r,d.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]}m.forEach(e=>h.has(e)),n.currentParents||(n.currentParents=[]);const y=u(n.currentScene,n.currentParents,r,m),S=[];for(let e of y){const n=g(e);S.push(l(n,...s))}c.sequence(S).onComplete(()=>{n.opened=!0,n.currentPage=r,n.currentParents=f[r].parents||null,o.changeContext(r),"function"==typeof f[r].afterShow&&f[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.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}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(([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 d=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,d=0;function m(){const e=o(a,d),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,d=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,d++,d>=o?(m(),void(o>1&&(p=setTimeout(()=>p=null,u)))):void(f=setTimeout(m,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,d++,d>=o?(m(),void(o>1&&(p=setTimeout(()=>p=null,u)))):void(f=setTimeout(m,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),d=0)}}}(a,f),d=u(a,f);d>0&&p.start();let m={getPrefix:()=>"click",shortcutName:e=>i(e),contextChange:()=>{d=u(a,f),d<1&&p.stop(),d>0&&p.start()},mute:()=>{p.stop()},unmute:()=>p.start(),destroy:()=>p.stop()};return Object.freeze(m),m},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 d=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,d=!1;const m=()=>p=!1,h=()=>p=!0,g=()=>d=!0,y=()=>!1===p;function v(){let e=a.map(e=>[e.join("+")]);const t={wait:m,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),d&&(e=e.slice(0,-1),d=!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,d=!1)}}}(f,p),m=r(f,p);m>0&&d.start();let h={getPrefix:()=>"key",shortcutName:e=>t(e),contextChange:e=>{m=r(f,p),m<1&&d.stop(),m>0&&d.start()},mute:()=>d.stop(),unmute:()=>d.start(),destroy:()=>d.stop()};return Object.freeze(h),h},shortcuts:p});function m(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(!t)return yield[e,"hide"],void(yield[n,"show"]);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 m.sequence=function(e,...t){const n=m(),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},m.all=function(e,...t){const n=m(),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||0}),r={currentScene:null,currentParents:null,sceneNames:new Set,scenes:{},opened:!1,jumpStack:[]},o={},s={shortcutMngr:t,findInstructions:k,askForPromise:m,setInstruction:C({askForPromise:m,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}=e;n.forEach(e=>{if(null==e)return;const{name:n,scene:o}=e;if(null==o)return void console.warn(`Scene ${n} is not defined`);o.parents||(o.parents=[]),t.scenes[n]=o,t.sceneNames.add(n);const{show:s,hide:i,parents:c,...u}=o,l={};l[n]=u,r.load(l)})}}(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:d,sceneNames:m,currentScene:h}=t;return h&&"function"==typeof d[h].beforeHide?(0,d[h].beforeHide)({done:f.done,dependencies:s.getDependencies()}):f.done(!0),f.onComplete(e=>{if(!e)return a.done(),a.promise;if(!m.has(n)&&c)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.currentPage=n,s.changeContext(n),a.done(),a.promise;const{show:f,parents:h=[]}=d[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=[...d[t.currentScene].parents]),t.currentScene=e;else{let n=d[e].parents.at(-1);t.currentScene=n}return d[e][n]}h.forEach(e=>m.has(e)),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.currentPage=n,t.currentParents=d[n].parents||null,s.changeContext(n),"function"==typeof d[n].afterShow&&d[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 d});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}});
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.5.0",
4
+ "version": "1.6.0",
5
5
  "license": "MIT",
6
6
  "author": "Peter Naydenov",
7
7
  "main": "./src/main.js",
@@ -20,13 +20,7 @@ function* findInstructions ( currentName, currentParents, targetName, targetPare
20
20
  }
21
21
 
22
22
  if ( 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
- }
28
23
  yield [ currentName, 'hide' ]
29
-
30
24
  if ( currentParents.includes ( targetName ) ) {
31
25
  let index = currentParents.indexOf ( targetName );
32
26
  let filtered = currentParents.filter ( (x,i) => i > index )
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;
@@ -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
 
@@ -24,8 +24,10 @@ function show ( dependencies, state ) {
24
24
 
25
25
  if ( hasBeforeHide ) { // Execute 'beforeUnload' function if exists
26
26
  const closingFn = scenes[currentScene].beforeHide;
27
+ // TODO: If async elements in beforeUnload, we will
28
+ // need full unloadTask and function should return a promise
27
29
  closingFn ({ done:unloadTask.done, dependencies: shortcutMngr.getDependencies() })
28
- } // if currentPage
30
+ } // if currentScene
29
31
  else unloadTask.done ( true )
30
32
 
31
33
 
@@ -38,21 +40,19 @@ function show ( dependencies, state ) {
38
40
  }
39
41
 
40
42
  if ( !sceneNames.has ( requestedScene ) ) {
41
- if ( log ) {
42
- log ({
43
- message: `Scene ${requestedScene} is not available.`
44
- , level : 1
45
- , type : 'error'
46
- })
47
- showTask.done ()
48
- return showTask.promise
49
- }
43
+ log ({
44
+ message: `Scene "${requestedScene}" is not available.`
45
+ , level : 1
46
+ , type : 'error'
47
+ })
48
+ showTask.done ()
49
+ return showTask.promise
50
50
  }
51
51
 
52
52
  if ( !opened && options.ssr ) { // Check for Server side rendering on first scene load only
53
53
  // Executes only once when the scene manager is started
54
54
  state.opened = true
55
- state.currentPage = requestedScene
55
+ state.currentScene = requestedScene
56
56
  shortcutMngr.changeContext ( requestedScene )
57
57
  showTask.done ()
58
58
  return showTask.promise
@@ -60,23 +60,22 @@ function show ( dependencies, state ) {
60
60
 
61
61
  const { show, parents=[] } = scenes[requestedScene];
62
62
 
63
- if ( parents[0] === '*' ) {
64
- show ().then ( () => showTask.done () )
65
- state.currentParents.push ( state.currentPage )
66
- state.currentPage = requestedScene
67
- return showTask.promise
68
- }
69
-
70
- let checkParents = parents.forEach ( name => sceneNames.has ( name ) ) || true ;
63
+ if ( parents[0] === '*' ) {
64
+ const overlayTask = setInstruction(show, ...args)()
65
+ overlayTask.then ( () => showTask.done () )
66
+ state.currentParents.push ( state.currentScene )
67
+ state.currentScene = requestedScene
68
+ return showTask.promise
69
+ }
70
+
71
+ let checkParents = ( parents.length === 0 ) ? true : parents.every ( name => sceneNames.has ( name ) )
71
72
 
72
73
  if ( !checkParents ) {
73
- if ( log ) {
74
- log ({
75
- message: `Some of '${requestedScene}' parent scenes are not set.`
76
- , level : 1
77
- , type : 'error'
78
- })
79
- }
74
+ log ({
75
+ message: `Some of '${requestedScene}' parent scenes are not set.`
76
+ , level : 1
77
+ , type : 'error'
78
+ })
80
79
  showTask.done ()
81
80
  return showTask.promise
82
81
  }
@@ -109,7 +108,7 @@ function show ( dependencies, state ) {
109
108
 
110
109
  goingTask.onComplete ( () => {
111
110
  state.opened = true
112
- state.currentPage = requestedScene
111
+ state.currentScene = requestedScene
113
112
  state.currentParents = scenes[requestedScene].parents || null
114
113
  shortcutMngr.changeContext ( requestedScene )
115
114
  if ( typeof scenes[requestedScene].afterShow === 'function' ) scenes[requestedScene].afterShow ({ dependencies: shortcutMngr.getDependencies(), done: () => {} })
@@ -16,7 +16,7 @@ describe ( 'Cuts integration', () => {
16
16
  { name: 'deep', scene: { show: ({task}) => { calls.push('show deep'); task.done() }, hide: ({task}) => { calls.push('hide deep'); task.done() }, parents: ['top', 'mid'] } }
17
17
  ]
18
18
 
19
- const script = cuts()
19
+ const script = cuts();
20
20
  script.setScenes ( scenes )
21
21
 
22
22
  await script.show ({ scene: 'top' })
@@ -31,12 +31,12 @@ describe ( 'Cuts integration', () => {
31
31
 
32
32
  await script.show ({ scene: 'top' })
33
33
  expect ( calls ).toEqual ([
34
- 'show top',
35
- 'show mid',
36
- 'show deep',
37
- 'hide deep',
38
- 'hide mid'
39
- ])
34
+ 'show top',
35
+ 'show mid',
36
+ 'show deep',
37
+ 'hide deep',
38
+ 'hide mid'
39
+ ])
40
40
 
41
41
  await script.show ({ scene: 'deep' })
42
42
  expect ( calls ).toEqual ([
@@ -52,5 +52,361 @@ describe ( 'Cuts integration', () => {
52
52
 
53
53
 
54
54
 
55
+ it ( 'Load plugins', async () => {
56
+ const script = cuts()
57
+ const plugins = await script.loadPlugins ( ['Key', 'Click'] )
58
+ expect ( plugins ).toHaveLength ( 2 )
59
+ }) // it Load plugins
60
+
61
+
62
+
63
+
64
+
65
+
66
+
67
+ it ( 'beforeHide', async () => {
68
+ const script = cuts ();
69
+ const calls = [];
70
+ const scenes = [
71
+ {
72
+ name: 'top'
73
+ , scene: {
74
+ show: ({task}) => { calls.push('show top'); task.done() },
75
+ hide: ({task}) => { calls.push('hide top'); task.done() } ,
76
+ // Prevent unload event:
77
+ 'beforeHide': ({ done }) => done ( false ) ,
78
+ 'click: left-1': () => calls.push('click left-1')
79
+ }
80
+ },
81
+ {
82
+ name: 'other'
83
+ , scene: {
84
+ show: ({task}) => { calls.push('show other'); task.done() },
85
+ hide: ({task}) => { calls.push('hide other'); task.done() }
86
+ }
87
+ }
88
+ ];
89
+
90
+ script.setScenes ( scenes )
91
+ await script.show ({ scene: 'top' })
92
+ expect ( calls ).toEqual (['show top'])
93
+
94
+ await script.show ({ scene: 'other' })
95
+ expect ( calls ).toEqual (['show top'])
96
+ expect ( script.getState().scene ).toEqual ( 'top' )
97
+ }) // it beforeHide
98
+
99
+
100
+
101
+ it ( 'Call no existing scene', async () => {
102
+ const script = cuts ({ logLevel : 1 });
103
+ const calls = [];
104
+ const scenes = [
105
+ {
106
+ name: 'top'
107
+ , scene: {
108
+ show: ({task}) => { calls.push('show top'); task.done() },
109
+ hide: ({task}) => { calls.push('hide top'); task.done() } ,
110
+ 'click: left-1': () => calls.push ( 'click left-1' ),
111
+ '@app-error': ( arg ) => {
112
+ calls.push ( 'app-error' )
113
+ expect ( arg.type ).toBe ( 'error' )
114
+ expect ( arg.message ).toBe ( 'Scene "any" is not available.' )
115
+ }
116
+ }
117
+ },
118
+ {
119
+ name: 'other'
120
+ , scene: {
121
+ show: ({task}) => { calls.push('show other'); task.done() },
122
+ hide: ({task}) => { calls.push('hide other'); task.done() }
123
+ }
124
+ }
125
+ ];
126
+
127
+ script.setScenes ( scenes )
128
+ await script.show ({ scene: 'top' })
129
+ expect ( calls ).toEqual (['show top'])
130
+
131
+ await script.show ({ scene: 'any' })
132
+ expect ( calls ).toEqual (['show top', 'app-error'])
133
+ expect ( script.getState().scene ).toEqual ( 'top' )
134
+ }) // it Call no existing scene
135
+
136
+
137
+
138
+ it ( 'Server side rendering (SSR)', async () => {
139
+ const script = cuts ();
140
+ const calls = [];
141
+ const scenes = [
142
+ {
143
+ name: 'home',
144
+ scene: {
145
+ show: ({task}) => { calls.push('show home'); task.done() },
146
+ hide: ({task}) => { calls.push('hide home'); task.done() }
147
+ }
148
+ }
149
+ ];
150
+
151
+ script.setScenes ( scenes )
152
+
153
+ // SSR mode: show without executing the scene's show function
154
+ await script.show({ scene: 'home', options: { ssr: true } })
155
+
156
+ expect(calls).toEqual([]); // show function should not be called
157
+ expect(script.getState().scene ).toBe ( 'home' )
158
+ expect(script.getState().opened ).toBe ( true )
159
+
160
+ // Subsequent show should execute normally
161
+ await script.show ({ scene: 'home' })
162
+ expect( calls ).toEqual(['hide home', 'show home'])
163
+ }) // it Server side rendering (SSR)
164
+
165
+
166
+
167
+ it ( 'Non existing parents error', async () => {
168
+ const script = cuts ();
169
+ const calls = [];
170
+ const scenes = [
171
+ {
172
+ name: 'child'
173
+ , scene: {
174
+ show: ({task}) => { calls.push('show child'); task.done() },
175
+ hide: ({task}) => { calls.push('hide child'); task.done() },
176
+ parents: [ 'nonexistent' ]
177
+ }
178
+ }
179
+ ];
180
+ script.setScenes ( scenes )
181
+ await script.show ({ scene: 'child' })
182
+ expect ( calls ).toEqual ([])
183
+ expect ( script.getState().scene ).toBe ( null )
184
+ }) // it Non existing parents error
185
+
186
+
187
+
188
+ it ( 'No name scene', async () => {
189
+ const script = cuts({ logLevel : 0 });
190
+ const scenes = [
191
+ {
192
+ scene: {
193
+ show: ({task}) => task.done(),
194
+ hide: ({task}) => task.done()
195
+ }
196
+ }
197
+ ];
198
+ script.setScenes ( scenes );
199
+ expect ( script.listScenes() ).toEqual ( [] );
200
+ }) // it No name scene
201
+
202
+
203
+
204
+ it ( 'No scene in definition', async () => {
205
+ const script = cuts({ logLevel : 0 });
206
+ const scenes = [ {name: 'top'} ];
207
+ script.setScenes ( scenes );
208
+ expect ( script.listScenes() ).toEqual ( [] );
209
+ }) // it No scene in definition
210
+
211
+
212
+
213
+ it ( 'List shortcuts', async () => {
214
+ const script = cuts ()
215
+ const calls = [];
216
+
217
+ const scenes = [
218
+ {
219
+ name: 'top'
220
+ , scene: {
221
+ show: ({task}) => { calls.push('show top'); task.done() },
222
+ hide: ({task}) => { calls.push('hide top'); task.done() } ,
223
+ 'click: left-1': () => calls.push('click left-1')
224
+ }
225
+ }
226
+ ];
227
+
228
+ script.setScenes ( scenes )
229
+ expect ( script.listShortcuts( 'top' ) ).toEqual ( ['click: left-1'] )
230
+ }) // it List shortcuts
231
+
232
+
233
+
234
+ it ( 'List shortcuts', async () => {
235
+ const script = cuts ()
236
+ const calls = [];
237
+
238
+ const scenes = [
239
+ {
240
+ name: 'top'
241
+ , scene: {
242
+ show: ({task}) => { calls.push('show top'); task.done() },
243
+ hide: ({task}) => { calls.push('hide top'); task.done() } ,
244
+ 'click: left-1': () => calls.push('click left-1')
245
+ }
246
+ }
247
+ ];
248
+
249
+ script.setScenes ( scenes )
250
+ expect ( script.listShortcuts( 'none' ) ).toEqual ( null )
251
+ }) // it List shortcuts
252
+
253
+
254
+
255
+ it ( 'Jump functionality', async () => {
256
+ const script = cuts({ logLevel : 0 });
257
+ const calls = [];
258
+ const scenes = [
259
+ {
260
+ name: 'home'
261
+ , scene: {
262
+ show: ({task}) => { calls.push('show home'); task.done() },
263
+ hide: ({task}) => { calls.push('hide home'); task.done() }
264
+ }
265
+ },
266
+ {
267
+ name: 'settings'
268
+ , scene: {
269
+ show: ({task}) => { calls.push('show settings'); task.done() },
270
+ hide: ({task}) => { calls.push('hide settings'); task.done() }
271
+ }
272
+ }
273
+ ];
274
+
275
+ script.setScenes ( scenes );
276
+
277
+ await script.show ({ scene: 'home' });
278
+ expect ( calls ).toEqual (['show home']);
279
+ expect ( script.getState().scene ).toEqual ( 'home' );
280
+
281
+ await script.jump ({ scene: 'settings' });
282
+ expect ( calls ).toEqual (['show home', 'hide home', 'show settings']);
283
+ expect ( script.getState().scene ).toEqual ( 'settings' );
284
+
285
+ await script.jumpBack ();
286
+ expect ( calls ).toEqual (['show home', 'hide home', 'show settings', 'hide settings', 'show home']);
287
+ expect ( script.getState().scene ).toEqual ( 'home' );
288
+ }) // it Jump functionality
289
+
290
+
291
+
292
+ it ( 'Jump with hops', async () => {
293
+ const script = cuts();
294
+ const calls = [];
295
+ const scenes = [
296
+ {
297
+ name: 'scene1'
298
+ , scene: {
299
+ show: ({task}) => { calls.push('show scene1'); task.done() },
300
+ hide: ({task}) => { calls.push('hide scene1'); task.done() }
301
+ }
302
+ },
303
+ {
304
+ name: 'scene2'
305
+ , scene: {
306
+ show: ({task}) => { calls.push('show scene2'); task.done() },
307
+ hide: ({task}) => { calls.push('hide scene2'); task.done() }
308
+ }
309
+ },
310
+ {
311
+ name: 'scene3'
312
+ , scene: {
313
+ show: ({task}) => { calls.push('show scene3'); task.done() },
314
+ hide: ({task}) => { calls.push('hide scene3'); task.done() }
315
+ }
316
+ }
317
+ ];
318
+
319
+ script.setScenes ( scenes );
320
+
321
+ await script.show ({ scene: 'scene1' });
322
+ expect ( script.getState().scene ).toEqual ( 'scene1' );
323
+
324
+ await script.jump ({ scene: 'scene2' });
325
+ expect ( script.getState().scene ).toEqual ( 'scene2' );
326
+
327
+ await script.jump ({ scene: 'scene3' });
328
+ expect ( script.getState().scene ).toEqual ( 'scene3' );
329
+
330
+ await script.jumpBack ({ hops: 2 });
331
+ expect ( script.getState().scene ).toEqual ( 'scene1' );
332
+ }) // it Jump with hops
333
+
334
+
335
+
336
+ it ( 'Jumps reset and jump back on empty stack', async () => {
337
+ const script = cuts();
338
+ const scenes = [
339
+ {
340
+ name: 'scene1'
341
+ , scene: {
342
+ show: ({task}) => task.done(),
343
+ hide: ({task}) => task.done()
344
+ }
345
+ },
346
+ {
347
+ name: 'scene2'
348
+ , scene: {
349
+ show: ({task}) => task.done(),
350
+ hide: ({task}) => task.done()
351
+ }
352
+ }
353
+ ];
354
+
355
+ script.setScenes ( scenes );
356
+
357
+ await script.show ({ scene: 'scene1' });
358
+ await script.jump ({ scene: 'scene2' });
359
+ expect ( script.getState().scene ).toEqual ( 'scene2' );
360
+
361
+ script.jumpsReset();
362
+
363
+ const result = await script.jumpBack();
364
+ expect ( result ).toBeUndefined();
365
+ expect ( script.getState().scene ).toEqual ( 'scene2' ); // scene should not change
366
+ }) // it Jumps reset and jump back on empty stack
367
+
368
+
369
+
370
+ it ( 'Show scene with wildcard parent', async () => {
371
+ // Test for scenes with parents: ['*']
372
+ // The '*' wildcard allows the scene to be shown as an overlay over any current scene
373
+ // without hiding the underlying scene. The previous scene is preserved in currentParents.
374
+ const script = cuts();
375
+ const calls = [];
376
+ const scenes = [
377
+ {
378
+ name: 'base'
379
+ , scene: {
380
+ show: ({task}) => { calls.push('show base'); task.done() },
381
+ hide: ({task}) => { calls.push('hide base'); task.done() }
382
+ }
383
+ },
384
+ {
385
+ name: 'overlay' // This scene uses '*' to indicate it can overlay any scene
386
+ , scene: {
387
+ show: ({task}) => {
388
+ calls.push ( 'show overlay' )
389
+ task.done ()
390
+ },
391
+ hide: ({task}) => { calls.push('hide overlay'); task.done() },
392
+ parents: ['*'] // '*' means this scene can be shown over any current scene
393
+ }
394
+ }
395
+ ];
396
+
397
+ script.setScenes ( scenes );
398
+
399
+ await script.show ({ scene: 'base' });
400
+ expect ( calls ).toEqual (['show base']);
401
+ expect ( script.getState().scene ).toEqual ( 'base' );
402
+ expect ( script.getState().parents ).toEqual ( [] );
403
+
404
+ await script.show ({ scene: 'overlay' });
405
+ expect ( calls ).toEqual (['show base', 'show overlay']); // Note: 'hide base' is not called
406
+ expect ( script.getState().scene ).toEqual ( 'overlay' );
407
+ expect ( script.getState().parents ).toEqual ( ['base'] ); // Previous scene is saved
408
+ }) // it Show scene with wildcard parent
409
+
410
+
55
411
 
56
- }) // describe
412
+ }) // describe
@@ -1 +1 @@
1
- {"version":3,"file":"findInstructions.d.ts","sourceRoot":"","sources":["../src/findInstructions.js"],"names":[],"mappings":";AAGA;;;;;;;;GAQG;AACH,+CANW,MAAM,GAAC,IAAI,kBACX,KAAK,CAAE,MAAM,CAAC,cACd,MAAM,iBACN,KAAK,CAAE,MAAM,CAAC,sCA+ExB"}
1
+ {"version":3,"file":"findInstructions.d.ts","sourceRoot":"","sources":["../src/findInstructions.js"],"names":[],"mappings":";AAGA;;;;;;;;GAQG;AACH,+CANW,MAAM,GAAC,IAAI,kBACX,KAAK,CAAE,MAAM,CAAC,cACd,MAAM,iBACN,KAAK,CAAE,MAAM,CAAC,sCAyExB"}
@@ -1 +1 @@
1
- {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.js"],"names":[],"mappings":";AAoCA;;;;;;;;;;;;;;;;;;;yBAyCmB,KAAK,0BAAc,GACjB,OAAO,CAAE,UAAU,CAAC;0BAgBtB,GAAC;uBAQC,GAAC;kBAMH,MAAM;kBAQJ,KAAK,CAAE,MAAM,CAAC;6CAQhB,GAAC;8BAQD,MAAM;;gBAuBL,MAAM,WACH,GAAC,EAAA;EAKvB"}
1
+ {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.js"],"names":[],"mappings":";AAoCA;;;;;;;;;;;;;;;;;;;yBA8CmB,KAAK,0BAAc,GACjB,OAAO,CAAE,UAAU,CAAC;0BAgBtB,GAAC;uBAQC,GAAC;kBAMH,MAAM;kBAQJ,KAAK,CAAE,MAAM,CAAC;6CAQhB,GAAC;8BAQD,MAAM;;gBAuBL,MAAM,WACH,GAAC,EAAA;EAKvB"}
@@ -1,9 +1,18 @@
1
1
  export default setScenes;
2
+ export type AskObject = {
3
+ /**
4
+ * - Mark the task as done
5
+ */
6
+ done: Function;
7
+ };
2
8
  export type SceneObject = {
3
9
  /**
4
10
  * - load interface and prerequisites for the scene;
5
11
  */
6
- show: Function;
12
+ show: (arg0: {
13
+ task: AskObject;
14
+ dependencies: any;
15
+ }) => void;
7
16
  /**
8
17
  * - run after scene is loaded. Optional. Returns true to continue loading, false to cancel;
9
18
  */
@@ -11,7 +20,10 @@ export type SceneObject = {
11
20
  /**
12
21
  * - Reverse the settings from 'show';
13
22
  */
14
- hide: () => void;
23
+ hide: (arg0: {
24
+ task: AskObject;
25
+ dependencies: any;
26
+ }) => void;
15
27
  /**
16
28
  * - Run before scene is hidden. Optional;
17
29
  */
@@ -35,11 +47,15 @@ export type sceneDescription = {
35
47
  */
36
48
  scene: SceneObject;
37
49
  };
50
+ /**
51
+ * @typedef {Object} AskObject
52
+ * @property {function} done - Mark the task as done
53
+ */
38
54
  /**
39
55
  * @typedef {Object} SceneObject
40
- * @property {function} show - load interface and prerequisites for the scene;
56
+ * @property {function({task: AskObject, dependencies: *}): void} show - load interface and prerequisites for the scene;
41
57
  * @property {function():boolean} [afterShow] - run after scene is loaded. Optional. Returns true to continue loading, false to cancel;
42
- * @property {function():void} hide - Reverse the settings from 'show';
58
+ * @property {function({task: AskObject, dependencies: *}): void} hide - Reverse the settings from 'show';
43
59
  * @property {function():void} [beforeHide] - Run before scene is hidden. Optional;
44
60
  * @property {Array.<string>} [parents] - list of parent scene names.
45
61
  * @property {*} ... - shortcut descriptions
@@ -1 +1 @@
1
- {"version":3,"file":"setScenes.d.ts","sourceRoot":"","sources":["../../src/methods/setScenes.js"],"names":[],"mappings":";;;;;;;;;gBAMc,MAAW,OAAO;;;;UAClB,MAAW,IAAI;;;;iBACf,MAAW,IAAI;;;;cACf,KAAK,CAAE,MAAM,CAAC;;;;QACd,GAAC;;;;;;UAOD,MAAM;;;;WACN,WAAW;;AAfzB;;;;;;;;GAQG;AAIH;;;;GAIG;AAKH,4DAOgC,MAJhB,gBAAgB,EAII,UAsBlC"}
1
+ {"version":3,"file":"setScenes.d.ts","sourceRoot":"","sources":["../../src/methods/setScenes.js"],"names":[],"mappings":";;;;;;;;;;;UASc,CAAS,IAAkC,EAAlC;QAAC,IAAI,EAAE,SAAS,CAAC;QAAC,YAAY,EAAE,GAAC,CAAA;KAAC,KAAG,IAAI;;;;gBAClD,MAAW,OAAO;;;;UAClB,CAAS,IAAkC,EAAlC;QAAC,IAAI,EAAE,SAAS,CAAC;QAAC,YAAY,EAAE,GAAC,CAAA;KAAC,KAAG,IAAI;;;;iBAClD,MAAW,IAAI;;;;cACf,KAAK,CAAE,MAAM,CAAC;;;;QACd,GAAC;;;;;;UAOD,MAAM;;;;WACN,WAAW;;AAnBzB;;;GAGG;AACH;;;;;;;;GAQG;AAIH;;;;GAIG;AAKH,4DAOgC,MAJhB,gBAAgB,EAII,UAkClC"}
@@ -1 +1 @@
1
- {"version":3,"file":"show.d.ts","sourceRoot":"","sources":["../../src/methods/show.js"],"names":[],"mappings":";AAIA,2FAKG;IAAwB,KAAK,EAArB,MAAM;IACW,OAAO,GAChC;QAAiC,GAAG,EAA5B,OAAO;KACf;CAAA,mCA6GF"}
1
+ {"version":3,"file":"show.d.ts","sourceRoot":"","sources":["../../src/methods/show.js"],"names":[],"mappings":";AAIA,2FAKG;IAAwB,KAAK,EAArB,MAAM;IACW,OAAO,GAChC;QAAiC,GAAG,EAA5B,OAAO;KACf;CAAA,mCA4GF"}