@peter.naydenov/cuts 1.4.4 → 1.5.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,6 +1,15 @@
1
1
  # Release History
2
2
 
3
3
 
4
+ ## 1.5.0 ( 2025-10-?? )
5
+ - [x] Dependency update. @peter.naydenov/shortcuts - v.3.5.1
6
+ - [x] Dev dependency update. Vitest - v.4.0.1
7
+ - [x] Cuts has event '@app-error'. Shortcut errors will trigger this event;
8
+ - [x] Type improvements;
9
+ - [x] New method `getState` returns an object with the current state;
10
+ - [x] Fix: Closing a long list of scenes breaks the state;
11
+
12
+
4
13
 
5
14
 
6
15
  ## 1.4.4 ( 2025-10-10)
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"),t=require("@peter.naydenov/log");function*r(e,n,t,r){let s=null;if(null===e)return yield*r.map(e=>[e,"show"]),void(yield[t,"show"]);if(!r||0===r.length)return n?(yield[e,"hide"],n.reverse(),yield*n.map(e=>[e,"hide"]),void(yield[t,"show"])):(yield[e,"hide"],void(yield[t,"show"]));if(r.includes(e)){for(let n=r.indexOf(e)+1;n<r.length;n++)yield[r[n],"show"];return void(yield[t,"show"])}if(!n)return yield[e,"hide"],void(yield*r.map(e=>[e,"show"]));if(r.every((e,t)=>n[t]===r[t]&&(s=t,!0)),null==s)return yield[e,"hide"],n.reverse(),yield*n.map(e=>[e,"hide"]),yield*r.map(e=>[e,"show"]),void(yield[t,"show"]);yield[e,"hide"];for(let e=n.length;e>s+1;e--)yield[n[e-1],"hide"];for(let e=s+1;e<r.length;e++)yield[r[e],"show"];yield[t,"show"]}function s(e){return function(n,...t){const{askForPromise:r,deps:s}=e;return function(){const e=r();return n({task:e,dependencies:s()},...t),e.promise}}}module.exports=function(o={logLevel:0}){const c=e.shortcuts(),i=o.logLevel||0,u=t({level:i}),d={currentScene:null,currentParents:null,sceneNames:new Set,scenes:{},opened:!1,jumpStack:[]},l={},a={shortcutMngr:c,findInstructions:r,askForPromise:n,setInstruction:s({askForPromise:n,deps:c.getDependencies}),log:u};return l.hide=function(e,n){return function(t=1){const{askForPromise:r,shortcutMngr:s,setInstruction:o}=e,{currentScene:c,currentParents:i,scenes:u}=n,d=r(),l=[],a=i.length>0;let p;return s.pause(),l.push(o(u[c].hide)),a||(n.currentScene=null),a&&"*"===t&&[...i].reverse().forEach(e=>{p=n.currentParents.pop(),n.currentScene=p,l.push(o(u[e].hide))}),a&&!["*",1].includes(t)&&i.slice("-"+(t-1)).reverse().map(e=>{p=n.currentParents.pop(),n.currentScene=p,l.push(o(u[e].hide))}),(t=r.sequence(l)).onComplete(()=>{s.changeContext(n.currentScene),d.done()}),d.promise}}(a,d),l.listShortcuts=function(e,n){return function(e){const{scenes:t,sceneNames:r}=n;if(!r.has(e))return null;const{show:s,hide:o,parents:c,beforeUnload:i,afterLoad:u,...d}=t[e];return Object.keys(d)}}(0,d),l.setScenes=function(e,n){return function(t){const{shortcutMngr:r}=e;t.forEach(e=>{if(null==e)return;const{name:t,scene:s}=e;if(null==s)return void console.warn(`Scene ${t} is not defined`);s.parents||(s.parents=[]),n.scenes[t]=s,n.sceneNames.add(t);const{show:o,hide:c,parents:i,...u}=s,d={};d[t]=u,r.load(d)})}}(a,d),l.show=function(e,n){return function({scene:t,options:r={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(t)&&i)return i({message:`Scene ${t} is not available.`,level:1,type:"error"}),l.done(),l.promise;if(!p&&r.ssr)return n.opened=!0,n.currentPage=t,o.changeContext(t),l.done(),l.promise;const{show:a,parents:m=[]}=h[t];if("*"===m[0])return a().then(()=>l.done()),n.currentParents.push(n.currentPage),n.currentPage=t,l.promise;function g([e,t]){if("show"===t)n.currentScene&&n.currentParents.push(n.currentScene),n.currentScene=e;else{let e=n.currentParents.pop();n.currentScene=e}return h[e][t]}m.forEach(e=>f.has(e)),n.currentParents||(n.currentParents=[]);const y=u(n.currentScene,n.currentParents,t,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(t),"function"==typeof h[t].afterShow&&h[t].afterShow({dependencies:o.getDependencies(),done:()=>{}}),l.done()})}),l.promise}}(a,d),l.jump=function(e,n){return function({scene:t},...r){return e.jumpStack.push(e.currentScene),n({scene:t},...r)}}(d,l.show),l.jumpBack=function(e,n){return function({hops:t}={hops:1},...r){for(let n=0;n<t-1;n++)e.jumpStack.pop();if(0===e.jumpStack.length)return;const s=e.jumpStack.pop();return n({scene:s},...r)}}(d,l.show),l.jumpsReset=function(e){return function(){e.jumpStack=[]}}(d),l.loadPlugins=async function(e){const n=e.map(e=>`plugin${e}`),t=await import("@peter.naydenov/shortcuts");return n.map(e=>t[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(!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};
package/dist/cuts.esm.mjs CHANGED
@@ -1 +1 @@
1
- import{shortcuts as e}from"@peter.naydenov/shortcuts";import n from"ask-for-promise";import t from"@peter.naydenov/log";function*r(e,n,t,r){let s=null;if(null===e)return yield*r.map(e=>[e,"show"]),void(yield[t,"show"]);if(!r||0===r.length)return n?(yield[e,"hide"],n.reverse(),yield*n.map(e=>[e,"hide"]),void(yield[t,"show"])):(yield[e,"hide"],void(yield[t,"show"]));if(r.includes(e)){for(let n=r.indexOf(e)+1;n<r.length;n++)yield[r[n],"show"];return void(yield[t,"show"])}if(!n)return yield[e,"hide"],void(yield*r.map(e=>[e,"show"]));if(r.every((e,t)=>n[t]===r[t]&&(s=t,!0)),null==s)return yield[e,"hide"],n.reverse(),yield*n.map(e=>[e,"hide"]),yield*r.map(e=>[e,"show"]),void(yield[t,"show"]);yield[e,"hide"];for(let e=n.length;e>s+1;e--)yield[n[e-1],"hide"];for(let e=s+1;e<r.length;e++)yield[r[e],"show"];yield[t,"show"]}function s(e){return function(n,...t){const{askForPromise:r,deps:s}=e;return function(){const e=r();return n({task:e,dependencies:s()},...t),e.promise}}}function o(o={logLevel:0}){const c=e(),i=o.logLevel||0,u=t({level:i}),d={currentScene:null,currentParents:null,sceneNames:new Set,scenes:{},opened:!1,jumpStack:[]},l={},a={shortcutMngr:c,findInstructions:r,askForPromise:n,setInstruction:s({askForPromise:n,deps:c.getDependencies}),log:u};return l.hide=function(e,n){return function(t=1){const{askForPromise:r,shortcutMngr:s,setInstruction:o}=e,{currentScene:c,currentParents:i,scenes:u}=n,d=r(),l=[],a=i.length>0;let p;return s.pause(),l.push(o(u[c].hide)),a||(n.currentScene=null),a&&"*"===t&&[...i].reverse().forEach(e=>{p=n.currentParents.pop(),n.currentScene=p,l.push(o(u[e].hide))}),a&&!["*",1].includes(t)&&i.slice("-"+(t-1)).reverse().map(e=>{p=n.currentParents.pop(),n.currentScene=p,l.push(o(u[e].hide))}),(t=r.sequence(l)).onComplete(()=>{s.changeContext(n.currentScene),d.done()}),d.promise}}(a,d),l.listShortcuts=function(e,n){return function(e){const{scenes:t,sceneNames:r}=n;if(!r.has(e))return null;const{show:s,hide:o,parents:c,beforeUnload:i,afterLoad:u,...d}=t[e];return Object.keys(d)}}(0,d),l.setScenes=function(e,n){return function(t){const{shortcutMngr:r}=e;t.forEach(e=>{if(null==e)return;const{name:t,scene:s}=e;if(null==s)return void console.warn(`Scene ${t} is not defined`);s.parents||(s.parents=[]),n.scenes[t]=s,n.sceneNames.add(t);const{show:o,hide:c,parents:i,...u}=s,d={};d[t]=u,r.load(d)})}}(a,d),l.show=function(e,n){return function({scene:t,options:r={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(t)&&i)return i({message:`Scene ${t} is not available.`,level:1,type:"error"}),l.done(),l.promise;if(!p&&r.ssr)return n.opened=!0,n.currentPage=t,o.changeContext(t),l.done(),l.promise;const{show:a,parents:m=[]}=h[t];if("*"===m[0])return a().then(()=>l.done()),n.currentParents.push(n.currentPage),n.currentPage=t,l.promise;function g([e,t]){if("show"===t)n.currentScene&&n.currentParents.push(n.currentScene),n.currentScene=e;else{let e=n.currentParents.pop();n.currentScene=e}return h[e][t]}m.forEach(e=>f.has(e)),n.currentParents||(n.currentParents=[]);const y=u(n.currentScene,n.currentParents,t,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(t),"function"==typeof h[t].afterShow&&h[t].afterShow({dependencies:o.getDependencies(),done:()=>{}}),l.done()})}),l.promise}}(a,d),l.jump=function(e,n){return function({scene:t},...r){return e.jumpStack.push(e.currentScene),n({scene:t},...r)}}(d,l.show),l.jumpBack=function(e,n){return function({hops:t}={hops:1},...r){for(let n=0;n<t-1;n++)e.jumpStack.pop();if(0===e.jumpStack.length)return;const s=e.jumpStack.pop();return n({scene:s},...r)}}(d,l.show),l.jumpsReset=function(e){return function(){e.jumpStack=[]}}(d),l.loadPlugins=async function(e){const n=e.map(e=>`plugin${e}`),t=await import("@peter.naydenov/shortcuts");return n.map(e=>t[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(!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};
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],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}=t,{ev:r}=e;return function(e=!1){const s=o.name;if(!e)return r.reset(),void(o.name=null);s!==e&&(n[e]?(n[s]&&r.reset(),o.name=e,t.plugins.forEach(t=>t.contextChange(e)),Object.entries(n[e]).forEach(([e,t])=>{t.forEach(t=>r.on(e,t))}),r.on("*",(...e)=>{t.exposeShortcut&&t.exposeShortcut(...e)})):r.emit("@shortcuts-error",`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}=t,{ev:r}=e;return function(e){n.name!==e?o[e]?delete o[e]:r.emit("shortcuts-error",`Context '${e}' does not exist`):r.emit("shortcuts-error",`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={}){const n=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)}}}(),o={},r={},s={currentContext:{name:null,note:null},shortcuts:{},plugins:[],exposeShortcut:!(!t.onShortcut||"function"!=typeof t.onShortcut)&&t.onShortcut},i={ev:n,inAPI:o,API:r,extra:{}};return r.enablePlugin=(e,t={})=>{const n=e.name;if(-1===o._systemAction(n,"none")){let n;n=e(i,s,t),s.plugins.push(n)}},r.disablePlugin=e=>{const t=o._systemAction(e,"destroy");-1!==t&&(s.plugins=s.plugins.filter((e,n)=>n!==t))},r.mutePlugin=e=>o._systemAction(e,"mute"),r.unmutePlugin=e=>o._systemAction(e,"unmute"),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=o._readShortcutWithPlugins(e);n.stop(t)},r.resume=(e="*")=>{const t=o._readShortcutWithPlugins(e);n.start(t)},r.emit=(e,...t)=>n.emit(o._readShortcutWithPlugins(e),...t),r.listContexts=()=>Object.keys(s.shortcuts),r.setDependencies=e=>i.extra={...i.extra,...e},r.getDependencies=()=>i.extra,Object.entries(e).forEach(([e,t])=>{e.startsWith("_")?o[e]=t(i,s):r[e]=t(i,s)}),r}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,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)}}}(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(),f=null,d=null}};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(),c=null,p=null}};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,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(),p=null,h=null}};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(),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 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}});
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.4",
4
+ "version": "1.5.0",
5
5
  "license": "MIT",
6
6
  "author": "Peter Naydenov",
7
7
  "main": "./src/main.js",
@@ -22,8 +22,8 @@
22
22
  "build": "rollup -c",
23
23
  "postbuild": "tsc -p tsconfig.json",
24
24
  "preview": "vite preview",
25
- "test": "mocha ./test-mocha/*.js",
26
- "cover": "c8 mocha test-mocha/*.js",
25
+ "test": "vitest",
26
+ "cover": "vitest run --coverage",
27
27
  "cypress": "cypress open --component --browser chrome"
28
28
  },
29
29
  "repository": {
@@ -32,38 +32,24 @@
32
32
  },
33
33
  "devDependencies": {
34
34
  "@peter.naydenov/visual-controller-for-vue3": "^2.1.6",
35
- "@rollup/plugin-commonjs": "^28.0.6",
36
- "@rollup/plugin-node-resolve": "^16.0.2",
35
+ "@rollup/plugin-commonjs": "^28.0.8",
36
+ "@rollup/plugin-node-resolve": "^16.0.3",
37
37
  "@rollup/plugin-terser": "^0.4.4",
38
- "@types/node": "^24.7.1",
38
+ "@types/node": "^24.9.1",
39
39
  "@vitejs/plugin-vue": "^6.0.1",
40
- "c8": "^10.1.3",
41
- "chai": "^6.2.0",
42
- "cypress": "^15.4.0",
43
- "mocha": "^11.7.4",
44
- "rollup": "^4.52.4",
40
+ "@vitest/coverage-v8": "^4.0.1",
41
+ "cypress": "^15.5.0",
42
+ "rollup": "^4.52.5",
45
43
  "typescript": "^5.9.3",
46
- "vite": "^7.1.9",
44
+ "vite": "^7.1.11",
45
+ "vitest": "^4.0.1",
47
46
  "vue": "^3.5.22"
48
47
  },
49
48
  "dependencies": {
50
49
  "@peter.naydenov/log": "^1.1.1",
51
- "@peter.naydenov/shortcuts": "^3.3.1",
50
+ "@peter.naydenov/shortcuts": "^3.5.1",
52
51
  "ask-for-promise": "^3.0.2"
53
52
  },
54
- "c8": {
55
- "include": [
56
- "src/**/*.js"
57
- ],
58
- "exclude": [
59
- "node_modules",
60
- "test"
61
- ],
62
- "reporter": [
63
- "lcov",
64
- "text-summary"
65
- ]
66
- },
67
53
  "keywords": [
68
54
  "script",
69
55
  "visual",
@@ -1,29 +1,48 @@
1
1
  'use strict'
2
2
 
3
3
 
4
+ /**
5
+ * @function findInstructions
6
+ * @description Generator that yields instructions for transitioning between scenes
7
+ * @param {string|null} currentName - current scene name
8
+ * @param {Array.<string>} currentParents - current scene parents
9
+ * @param {string} targetName - target scene name
10
+ * @param {Array.<string>} targetParents - target scene parents
11
+ * @yields {Array.<string, 'show'|'hide'>} - instruction array with scene name and action
12
+ */
4
13
  function* findInstructions ( currentName, currentParents, targetName, targetParents ) {
5
- let backToName, backIndex=null;
6
-
14
+ let backToName, backIndex=null, isNoParent=true;
15
+
7
16
  if ( currentName === null ) { // When the scene manager is just started
8
17
  yield* targetParents.map ( name => [ name, 'show' ])
9
18
  yield [ targetName, 'show' ]
10
19
  return
11
20
  }
12
21
 
13
- if ( !targetParents || targetParents.length === 0 ) { // Need to close all current parents, then open the target
22
+ if ( targetParents.length === 0 ) { // Need to close all current parents, then open the target
14
23
  if ( !currentParents ) {
15
24
  yield [ currentName, 'hide' ]
16
25
  yield [ targetName, 'show' ]
17
26
  return
18
27
  }
19
28
  yield [ currentName, 'hide' ]
20
- currentParents.reverse ()
21
- yield* currentParents.map ( name => [ name, 'hide' ])
22
- yield [ targetName, 'show' ]
29
+
30
+ if ( currentParents.includes ( targetName ) ) {
31
+ let index = currentParents.indexOf ( targetName );
32
+ let filtered = currentParents.filter ( (x,i) => i > index )
33
+ filtered.reverse ()
34
+ yield* filtered.map ( name => [ name, 'hide' ])
35
+ isNoParent = false
36
+ } else {
37
+ let cp = [...currentParents]
38
+ cp.reverse ()
39
+ yield* cp.map ( name => [ name, 'hide' ])
40
+ }
41
+ if ( isNoParent ) yield [ targetName, 'show' ]
23
42
  return
24
43
  }
25
44
 
26
- if ( targetParents.includes ( currentName ) ) { // Target is a subpage of the current page. No closing needed.
45
+ if ( targetParents.includes ( currentName ) ) { // Target is a subscene of the current scene. No closing needed.
27
46
  let id = targetParents.indexOf ( currentName );
28
47
  for ( let i = id+1; i < targetParents.length; i++ ) {
29
48
  yield [ targetParents[i], 'show' ]
@@ -58,6 +77,7 @@ function* findInstructions ( currentName, currentParents, targetName, targetPare
58
77
  return
59
78
  }
60
79
 
80
+
61
81
  yield [ currentName, 'hide' ]
62
82
  for ( let i = currentParents.length; i > backIndex+1; i-- ) {
63
83
  yield [ currentParents[i-1], 'hide' ]
package/src/main.js CHANGED
@@ -36,7 +36,7 @@ import jumpsReset from './methods/jumpsReset.js'
36
36
 
37
37
  function main ( cfg= {logLevel:0} ) {
38
38
  const
39
- shortcutMngr = shortcuts ()
39
+ shortcutMngr = shortcuts ({ errorEventName: '@app-error' })
40
40
  , logLevel = cfg.logLevel || 0
41
41
  , log = createLog ({ level:logLevel })
42
42
  , state = {
@@ -134,16 +134,29 @@ function main ( cfg= {logLevel:0} ) {
134
134
  * @returns void
135
135
  */
136
136
  API.disablePlugin = ( pluginName ) => shortcutMngr.disablePlugin ( pluginName )
137
-
138
-
137
+
139
138
  /**
140
- * @function emit
141
- * @description Emit an event
142
- * @param {string} event - event name
143
- * @param {...*} args - Extra data to pass to the listeners
144
- * @param {*} data - event data
145
- * @returns void
139
+ * Get the current state of the application
140
+ * @function getState
141
+ * @returns {Object} with properties:
142
+ * - scene: current scene name
143
+ * - parents: current parent scene names
144
+ * - opened: boolean indicating if the application is opened
146
145
  */
146
+ API.getState = () => ({
147
+ scene : state.currentScene
148
+ , parents : state.currentParents
149
+ , opened : state.opened
150
+ })
151
+
152
+
153
+ /**
154
+ * @function emit
155
+ * @description Emit an event
156
+ * @param {string} event - event name
157
+ * @param {...*} args - Extra data to pass to the listeners
158
+ * @returns void
159
+ */
147
160
  API.emit = ( event, ...args ) => shortcutMngr.emit ( event, ...args )
148
161
  return API
149
162
  } // main func.
@@ -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,4 +1,12 @@
1
1
  function jump ( state, show ) {
2
+ /**
3
+ * @function jump
4
+ * @description Jump to a scene, saving the current scene on the jump stack for later return
5
+ * @param {Object} request - request object
6
+ * @param {string} request.scene - target scene name
7
+ * @param {Array} [args] - arguments to pass to the scene method
8
+ * @returns {Promise} - promise that resolves when the jump is completed
9
+ */
2
10
  function jump ( { scene }, ...args ) {
3
11
  state.jumpStack.push ( state.currentScene )
4
12
  return show ( { scene }, ...args )
@@ -1,4 +1,12 @@
1
1
  function jumpBack ( state, show ) {
2
+ /**
3
+ * @function jumpBack
4
+ * @description Jump back to a previous scene from the jump stack
5
+ * @param {Object} [options] - options object
6
+ * @param {number} [options.hops=1] - number of hops to jump back
7
+ * @param {Array} [args] - arguments to pass to the scene method
8
+ * @returns {Promise|undefined} - promise that resolves when the jump back is completed, or undefined if no scenes in stack
9
+ */
2
10
  function jumpBack ({hops}={hops:1}, ...args ) {
3
11
  for ( let i = 0; i < hops-1; i++ ) {
4
12
  state.jumpStack.pop ()
@@ -1,4 +1,9 @@
1
1
  function jumpsReset ( state ) {
2
+ /**
3
+ * @function jumpsReset
4
+ * @description Reset the jump stack, clearing all saved jump positions
5
+ * @returns {void}
6
+ */
2
7
  return function jumpReset () {
3
8
  state.jumpStack = []
4
9
  }
@@ -3,32 +3,32 @@
3
3
 
4
4
  /**
5
5
  * @typedef {Object} SceneObject
6
- * @param {function} show - load interface and prerequisites for the scene;
7
- * @param {function():boolean} [afterShow] - run after scene is loaded. Optional. Returns true to continue loading, false to cancel;
8
- * @param {function():void} hide - Reverse the settings from 'show';
9
- * @param {function():void} [beforeHide] - Run before scene is hidden. Optional;
10
- * @param {Array.<string>} [parents] - list of parent scene names.
11
- * @param {*} ... - shortcut descriptions
6
+ * @property {function} show - load interface and prerequisites for the scene;
7
+ * @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';
9
+ * @property {function():void} [beforeHide] - Run before scene is hidden. Optional;
10
+ * @property {Array.<string>} [parents] - list of parent scene names.
11
+ * @property {*} ... - shortcut descriptions
12
12
  */
13
13
 
14
14
 
15
15
 
16
- /**
16
+ /**
17
17
  * @typedef {Object} sceneDescription
18
- * @param {string} name - name of the scene
19
- * @param {SceneObject} scene - object should contain 'show' and 'hide' + shortcuts and action functions
18
+ * @property {string} name - name of the scene
19
+ * @property {SceneObject} scene - object should contain 'show' and 'hide' + shortcuts and action functions
20
20
  */
21
21
 
22
22
 
23
23
 
24
24
 
25
25
  function setScenes ( dependencies, state ) {
26
- /**
27
- * @function setScenes
28
- * @param {SceneDescription[]} list - list of objects with name and scene. Scene should be a Scene model.
29
- * @returns void
30
- * @description Screen Description is an object with fields 'name' and 'scene'
31
- */
26
+ /**
27
+ * @function setScenes
28
+ * @param {sceneDescription[]} list - list of objects with name and scene. Scene should be a Scene model.
29
+ * @returns void
30
+ * @description Screen Description is an object with fields 'name' and 'scene'
31
+ */
32
32
  return function setScenes ( list ) {
33
33
  const { shortcutMngr } = dependencies;
34
34
  list.forEach ( item => {
@@ -18,20 +18,18 @@ function show ( dependencies, state ) {
18
18
  { shortcutMngr, askForPromise, log, findInstructions, setInstruction } = dependencies
19
19
  , showTask = askForPromise ()
20
20
  , unloadTask = askForPromise ()
21
- , { opened, scenes, sceneNames, currentPage } = state
21
+ , { opened, scenes, sceneNames, currentScene } = state
22
+ , hasBeforeHide = currentScene && (typeof scenes[currentScene].beforeHide === 'function')
22
23
  ;
23
24
 
24
- if ( currentPage ) { // Execute 'beforeUnload' function if exists
25
- const closingFn = scenes[currentPage].beforeHide;
26
- if ( typeof closingFn === 'function' ) {
27
- closingFn ({ done:unloadTask.done, dependencies: shortcutMngr.getDependencies() })
28
- }
25
+ if ( hasBeforeHide ) { // Execute 'beforeUnload' function if exists
26
+ const closingFn = scenes[currentScene].beforeHide;
27
+ closingFn ({ done:unloadTask.done, dependencies: shortcutMngr.getDependencies() })
29
28
  } // if currentPage
30
29
  else unloadTask.done ( true )
31
30
 
32
31
 
33
32
  unloadTask.onComplete ( continueLoading => {
34
-
35
33
  if ( !continueLoading ) {
36
34
  // if the 'beforeUnload' function returns false
37
35
  // Cancel loading the new scene
@@ -70,10 +68,11 @@ function show ( dependencies, state ) {
70
68
  }
71
69
 
72
70
  let checkParents = parents.forEach ( name => sceneNames.has ( name ) ) || true ;
71
+
73
72
  if ( !checkParents ) {
74
73
  if ( log ) {
75
74
  log ({
76
- message: `Some of '${requestedScene}' parent scenes are not set.`
75
+ message: `Some of '${requestedScene}' parent scenes are not set.`
77
76
  , level : 1
78
77
  , type : 'error'
79
78
  })
@@ -82,13 +81,13 @@ function show ( dependencies, state ) {
82
81
  return showTask.promise
83
82
  }
84
83
 
85
- function getStep ([name, action]) { // Returns a scene function(hide or show) according to instructions
84
+ function getStep ([name, action]) { // Returns a scene function(hide or show) according to instructions
86
85
  if ( action === 'show' ) {
87
- if ( state.currentScene ) state.currentParents.push ( state.currentScene )
86
+ if ( state.currentScene ) state.currentParents = [...scenes[state.currentScene].parents]
88
87
  state.currentScene = name
89
88
  }
90
89
  else {
91
- let el = state.currentParents.pop ();
90
+ let el = scenes[name].parents.at ( -1 )
92
91
  state.currentScene = el
93
92
  }
94
93
  return scenes[name][action]
@@ -96,22 +95,22 @@ function show ( dependencies, state ) {
96
95
 
97
96
  if ( !state.currentParents ) state.currentParents = []
98
97
  const
99
- g = findInstructions ( state.currentScene, state.currentParents, requestedScene, parents )
98
+ g = findInstructions ( state.currentScene, state.currentParents, requestedScene, parents )
100
99
  , instructions = []
101
100
  ;
102
-
103
- for ( let inst of g ) {
104
- [inst]
105
- .map ( getStep )
106
- .map ( step => instructions.push ( setInstruction(step),...args ))
107
- // Note: Methods 'show' and 'hide' are async, but we need to provide them a data,
108
- // so we need to wrap them in a another function that returns a promise
109
- }
110
-
101
+
102
+ for ( let inst of g ) {
103
+ const step = getStep ( inst )
104
+ instructions.push ( setInstruction(step, ...args) )
105
+ // Note: Methods 'show' and 'hide' are async, but we need to provide them a data,
106
+ // so we need to wrap them in a another function that returns a promise
107
+ }
111
108
  const goingTask = askForPromise.sequence ( instructions ); // Execute open steps(show and hide) in sequence
112
109
 
113
110
  goingTask.onComplete ( () => {
114
111
  state.opened = true
112
+ state.currentPage = requestedScene
113
+ state.currentParents = scenes[requestedScene].parents || null
115
114
  shortcutMngr.changeContext ( requestedScene )
116
115
  if ( typeof scenes[requestedScene].afterShow === 'function' ) scenes[requestedScene].afterShow ({ dependencies: shortcutMngr.getDependencies(), done: () => {} })
117
116
  showTask.done ()
@@ -1,6 +1,13 @@
1
1
  'use strict'
2
2
 
3
3
  function setInstruction ( dependencies ) {
4
+ /**
5
+ * @function setInstruction
6
+ * @description Wrap a scene function (show/hide) to return a promise-based instruction
7
+ * @param {function} fn - the scene function to wrap
8
+ * @param {...*} args - arguments to pass to the scene function
9
+ * @returns {function} - a function that returns a promise when executed
10
+ */
4
11
  return function setInstruction ( fn, ...args ) {
5
12
  const { askForPromise, deps } = dependencies;
6
13
  return function applyInstruction () {
@@ -0,0 +1,119 @@
1
+ import { describe, it, expect } from 'vitest'
2
+ import findInstructions from "../src/findInstructions.js"
3
+
4
+
5
+
6
+ describe ( 'Find a Position', () => {
7
+
8
+
9
+
10
+ it ( 'Switch top level scenes', () => {
11
+ let result = []
12
+ let g = findInstructions ( 'old', [], 'new', [] )
13
+
14
+ for (const n of g) { result.push(n) }
15
+
16
+ expect(result.length).toBe ( 2 )
17
+ expect(result[0][0]).toBe ( 'old' )
18
+ expect(result[0][1]).toBe ( 'hide' )
19
+
20
+ expect(result[1][0]).toBe ( 'new' )
21
+ expect(result[1][1]).toBe ( 'show' )
22
+ }) // it switch top level scenes
23
+
24
+
25
+
26
+ it ( 'Switch from child scene to top level scene', () => {
27
+ let result = []
28
+ let g = findInstructions ( 'old', ['one', 'two'], 'new', [] )
29
+
30
+ for (const n of g) { result.push(n) }
31
+
32
+ expect(result[0]).toEqual(['old', 'hide'])
33
+ expect(result[1]).toEqual(['two', 'hide'])
34
+ expect(result[2]).toEqual(['one', 'hide'])
35
+ expect(result[3]).toEqual(['new', 'show'])
36
+ }) // it switch from child scene to top level scene
37
+
38
+
39
+
40
+ it ( 'Switch to child scene', () => {
41
+ let result = []
42
+ let g = findInstructions ( 'old', ['bla'], 'new', ['old', 'two', 'three'])
43
+ for (const n of g) { result.push(n) }
44
+
45
+ expect(result).toHaveLength(3)
46
+ expect(result[0]).toEqual(['two', 'show'])
47
+ expect(result[1]).toEqual(['three', 'show'])
48
+ expect(result[2]).toEqual(['new', 'show'])
49
+ }) // it switch to child scene
50
+
51
+
52
+
53
+ it ( 'From child scene to other siblings scene', () => {
54
+ let result = []
55
+ let g = findInstructions('old', ['two', 'three'], 'new', ['two', 'three'])
56
+ for (const n of g) { result.push(n) }
57
+
58
+ expect(result).toHaveLength ( 2 )
59
+ expect(result[0]).toEqual(['old', 'hide'])
60
+ expect(result[1]).toEqual(['new', 'show'])
61
+ }) // it from top level scene to not own child scene
62
+
63
+
64
+
65
+ it ( 'From top level scene to not own child scene', () => {
66
+ let result = []
67
+ let g = findInstructions('old', undefined, 'new', ['two', 'three'])
68
+ for (const n of g) { result.push(n) }
69
+
70
+ expect(result).toHaveLength(3)
71
+ expect(result[0]).toEqual(['old', 'hide'])
72
+ expect(result[1]).toEqual(['two', 'show'])
73
+ expect(result[2]).toEqual(['three', 'show'])
74
+ }) // it from top level scene to not own child scene
75
+
76
+
77
+
78
+ it ( 'Long chain of parents', () => {
79
+ let result = []
80
+ let g = findInstructions('old', ['one', 'branch'], 'new', ['one', 'two', 'three'])
81
+ for (const n of g) { result.push(n) }
82
+
83
+ expect(result).toHaveLength(5)
84
+ expect(result[0]).toEqual(['old', 'hide'])
85
+ expect(result[1]).toEqual(['branch', 'hide'])
86
+ expect(result[2]).toEqual(['two', 'show'])
87
+ expect(result[3]).toEqual(['three', 'show'])
88
+ expect(result[4]).toEqual(['new', 'show'])
89
+ }) // it long chain of parents
90
+
91
+
92
+
93
+ it ( 'Different branches', () => {
94
+ let result = []
95
+ let g = findInstructions('old', ['something', 'branch'], 'new', ['one', 'two', 'three'])
96
+ for (const n of g) { result.push(n) }
97
+
98
+ expect(result).toHaveLength(7)
99
+ expect(result[0]).toEqual(['old', 'hide'])
100
+ expect(result[1]).toEqual(['branch', 'hide'])
101
+ expect(result[2]).toEqual(['something', 'hide'])
102
+ expect(result[3]).toEqual(['one', 'show'])
103
+ expect(result[4]).toEqual(['two', 'show'])
104
+ expect(result[5]).toEqual(['three', 'show'])
105
+ expect(result[6]).toEqual(['new', 'show'])
106
+ }) // it long chain of parents
107
+
108
+
109
+
110
+ it ( 'Target scene is in the list of parents of the current scene', () => {
111
+ let result = []
112
+ let g = findInstructions ( 'token-get-role', ['tokens', 'token-pop'], 'tokens', [] )
113
+ for (const n of g) { result.push(n) }
114
+ expect ( result ).toHaveLength ( 2 )
115
+ expect ( result[0] ).toEqual ( [ 'token-get-role', 'hide' ])
116
+ expect ( result[1] ).toEqual ( [ 'token-pop', 'hide' ])
117
+ }) // it Target scene is in the list of parents of the current scene
118
+
119
+ }) // describe
@@ -0,0 +1,56 @@
1
+ import { describe, it, expect } from 'vitest'
2
+ import cuts from "../src/main.js"
3
+
4
+
5
+
6
+ describe ( 'Cuts integration', () => {
7
+
8
+
9
+
10
+ it ( 'Open a scene, and 2 levels deep child', async () => {
11
+ const calls = [];
12
+
13
+ const scenes = [
14
+ { name: 'top', scene: { show: ({task}) => { calls.push('show top'); task.done() }, hide: ({task}) => { calls.push('hide top'); task.done() } } },
15
+ { name: 'mid', scene: { show: ({task}) => { calls.push('show mid'); task.done() }, hide: ({task}) => { calls.push('hide mid'); task.done() }, parents: ['top'] } },
16
+ { name: 'deep', scene: { show: ({task}) => { calls.push('show deep'); task.done() }, hide: ({task}) => { calls.push('hide deep'); task.done() }, parents: ['top', 'mid'] } }
17
+ ]
18
+
19
+ const script = cuts()
20
+ script.setScenes ( scenes )
21
+
22
+ await script.show ({ scene: 'top' })
23
+ expect ( calls ).toEqual ([ 'show top' ])
24
+
25
+ await script.show ({ scene: 'deep' })
26
+ expect ( calls ).toEqual ([
27
+ 'show top',
28
+ 'show mid',
29
+ 'show deep'
30
+ ])
31
+
32
+ await script.show ({ scene: 'top' })
33
+ expect ( calls ).toEqual ([
34
+ 'show top',
35
+ 'show mid',
36
+ 'show deep',
37
+ 'hide deep',
38
+ 'hide mid'
39
+ ])
40
+
41
+ await script.show ({ scene: 'deep' })
42
+ expect ( calls ).toEqual ([
43
+ 'show top',
44
+ 'show mid',
45
+ 'show deep',
46
+ 'hide deep',
47
+ 'hide mid',
48
+ 'show mid',
49
+ 'show deep'
50
+ ])
51
+ }) // it Open a scene, and 2 levels deep child
52
+
53
+
54
+
55
+
56
+ }) // describe
package/tsconfig.json CHANGED
@@ -5,6 +5,9 @@
5
5
  "declaration": true,
6
6
  "emitDeclarationOnly": true,
7
7
  "outDir": "types",
8
- "declarationMap": true
8
+ "declarationMap": true,
9
+ "moduleResolution": "bundler",
10
+ "target": "ES2022",
11
+ "module": "ES2022"
9
12
  }
10
13
  }
@@ -1,3 +1,12 @@
1
1
  export default findInstructions;
2
- declare function findInstructions(currentName: any, currentParents: any, targetName: any, targetParents: any): Generator<any, void, any>;
2
+ /**
3
+ * @function findInstructions
4
+ * @description Generator that yields instructions for transitioning between scenes
5
+ * @param {string|null} currentName - current scene name
6
+ * @param {Array.<string>} currentParents - current scene parents
7
+ * @param {string} targetName - target scene name
8
+ * @param {Array.<string>} targetParents - target scene parents
9
+ * @yields {Array.<string, 'show'|'hide'>} - instruction array with scene name and action
10
+ */
11
+ declare function findInstructions(currentName: string | null, currentParents: Array<string>, targetName: string, targetParents: Array<string>): Generator<string[], void, unknown>;
3
12
  //# sourceMappingURL=findInstructions.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"findInstructions.d.ts","sourceRoot":"","sources":["../src/findInstructions.js"],"names":[],"mappings":";AAGA,yIAiEC"}
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"}
package/types/main.d.ts CHANGED
@@ -4,7 +4,7 @@ declare function main(cfg?: {
4
4
  }): {
5
5
  hide: (endSteps?: number | string) => Promise<any>;
6
6
  listShortcuts: (sceneName: string) => (Array<string> | null);
7
- setScenes: (list: SceneDescription[]) => void;
7
+ setScenes: (list: import("./methods/setScenes.js").sceneDescription[]) => void;
8
8
  show: ({ scene: requestedScene, options }: {
9
9
  scene: string;
10
10
  options?: {
@@ -12,19 +12,20 @@ declare function main(cfg?: {
12
12
  };
13
13
  }, ...args?: any[]) => Promise<any>;
14
14
  jump: ({ scene }: {
15
- scene: any;
16
- }, ...args: any[]) => any;
15
+ scene: string;
16
+ }, ...args?: any[]) => Promise<any>;
17
17
  jumpBack: ({ hops }?: {
18
- hops: number;
19
- }, ...args: any[]) => any;
18
+ hops?: number;
19
+ }, ...args?: any[]) => Promise<any> | undefined;
20
20
  jumpsReset: () => void;
21
21
  loadPlugins(plugins: Array<"Key" | "Click" | "Form">): Promise<Function[]>;
22
- setDependencies(deps: any): any;
22
+ setDependencies(deps: any): void;
23
23
  getDependencies(): any;
24
24
  setNote(note: string): any;
25
25
  listScenes(): Array<string>;
26
- enablePlugin(plugin: Function, options?: any): any;
27
- disablePlugin(pluginName: string): any;
28
- emit(event: string, ...args: any[]): any;
26
+ enablePlugin(plugin: Function, options?: any): void;
27
+ disablePlugin(pluginName: string): void;
28
+ getState(): any;
29
+ emit(event: string, ...args: any[]): void;
29
30
  };
30
31
  //# sourceMappingURL=main.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.js"],"names":[],"mappings":";AAoCA;;;;;sBAhBmB,gBAAgB;;;;;;;;;;;;;;yBAyDhB,KAAK,0BAAc,GACjB,OAAO,CAAE,UAAU,CAAC;0BAgBtB,GAAC;uBAQC,GAAC;kBAMH,MAAM;kBAQJ,KAAK,CAAE,MAAM,CAAC;6CAQhB,GAAC;8BAQD,MAAM;gBASN,MAAM,WACH,GAAC,EAAA;EAMtB"}
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,5 +1,5 @@
1
1
  export default jump;
2
2
  declare function jump(state: any, show: any): ({ scene }: {
3
- scene: any;
4
- }, ...args: any[]) => any;
3
+ scene: string;
4
+ }, ...args?: any[]) => Promise<any>;
5
5
  //# sourceMappingURL=jump.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"jump.d.ts","sourceRoot":"","sources":["../../src/methods/jump.js"],"names":[],"mappings":";AAAA;;0BAMC"}
1
+ {"version":3,"file":"jump.d.ts","sourceRoot":"","sources":["../../src/methods/jump.js"],"names":[],"mappings":";AAAA,0DAKO;IAAwB,KAAK,EAArB,MAAM;CACd,mCAQN"}
@@ -1,5 +1,5 @@
1
1
  export default jumpBack;
2
2
  declare function jumpBack(state: any, show: any): ({ hops }?: {
3
- hops: number;
4
- }, ...args: any[]) => any;
3
+ hops?: number;
4
+ }, ...args?: any[]) => Promise<any> | undefined;
5
5
  //# sourceMappingURL=jumpBack.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"jumpBack.d.ts","sourceRoot":"","sources":["../../src/methods/jumpBack.js"],"names":[],"mappings":";AAAA;;0BAUC"}
1
+ {"version":3,"file":"jumpBack.d.ts","sourceRoot":"","sources":["../../src/methods/jumpBack.js"],"names":[],"mappings":";AAAA,8DAKO;IAAyB,IAAI,GAArB,MAAM;CACd,sBACU,eAAQ,SAAS,CAWjC"}
@@ -1 +1 @@
1
- {"version":3,"file":"jumpsReset.d.ts","sourceRoot":"","sources":["../../src/methods/jumpsReset.js"],"names":[],"mappings":";AAAA,oDAIC"}
1
+ {"version":3,"file":"jumpsReset.d.ts","sourceRoot":"","sources":["../../src/methods/jumpsReset.js"],"names":[],"mappings":";AAAA,+CAIiB,IAAI,CAKpB"}
@@ -1,19 +1,53 @@
1
1
  export default setScenes;
2
- export type SceneObject = any;
3
- export type sceneDescription = any;
2
+ export type SceneObject = {
3
+ /**
4
+ * - load interface and prerequisites for the scene;
5
+ */
6
+ show: Function;
7
+ /**
8
+ * - run after scene is loaded. Optional. Returns true to continue loading, false to cancel;
9
+ */
10
+ afterShow?: () => boolean;
11
+ /**
12
+ * - Reverse the settings from 'show';
13
+ */
14
+ hide: () => void;
15
+ /**
16
+ * - Run before scene is hidden. Optional;
17
+ */
18
+ beforeHide?: () => void;
19
+ /**
20
+ * - list of parent scene names.
21
+ */
22
+ parents?: Array<string>;
23
+ /**
24
+ * - shortcut descriptions
25
+ */
26
+ "": any;
27
+ };
28
+ export type sceneDescription = {
29
+ /**
30
+ * - name of the scene
31
+ */
32
+ name: string;
33
+ /**
34
+ * - object should contain 'show' and 'hide' + shortcuts and action functions
35
+ */
36
+ scene: SceneObject;
37
+ };
4
38
  /**
5
39
  * @typedef {Object} SceneObject
6
- * @param {function} show - load interface and prerequisites for the scene;
7
- * @param {function():boolean} [afterShow] - run after scene is loaded. Optional. Returns true to continue loading, false to cancel;
8
- * @param {function():void} hide - Reverse the settings from 'show';
9
- * @param {function():void} [beforeHide] - Run before scene is hidden. Optional;
10
- * @param {Array.<string>} [parents] - list of parent scene names.
11
- * @param {*} ... - shortcut descriptions
40
+ * @property {function} show - load interface and prerequisites for the scene;
41
+ * @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';
43
+ * @property {function():void} [beforeHide] - Run before scene is hidden. Optional;
44
+ * @property {Array.<string>} [parents] - list of parent scene names.
45
+ * @property {*} ... - shortcut descriptions
12
46
  */
13
47
  /**
14
48
  * @typedef {Object} sceneDescription
15
- * @param {string} name - name of the scene
16
- * @param {SceneObject} scene - object should contain 'show' and 'hide' + shortcuts and action functions
49
+ * @property {string} name - name of the scene
50
+ * @property {SceneObject} scene - object should contain 'show' and 'hide' + shortcuts and action functions
17
51
  */
18
- declare function setScenes(dependencies: any, state: any): (list: SceneDescription[]) => void;
52
+ declare function setScenes(dependencies: any, state: any): (list: sceneDescription[]) => void;
19
53
  //# sourceMappingURL=setScenes.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"setScenes.d.ts","sourceRoot":"","sources":["../../src/methods/setScenes.js"],"names":[],"mappings":";;;AAGA;;;;;;;;GAQG;AAIH;;;;GAIG;AAKH,4DAOgC,MAJjB,gBAAgB,EAIK,UAsBlC"}
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 +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,mCA8GF"}
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,3 +1,3 @@
1
1
  export default setInstruction;
2
- declare function setInstruction(dependencies: any): (fn: any, ...args: any[]) => () => any;
2
+ declare function setInstruction(dependencies: any): (fn: Function, ...args: any[]) => Function;
3
3
  //# sourceMappingURL=setInstruction.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"setInstruction.d.ts","sourceRoot":"","sources":["../src/setInstruction.js"],"names":[],"mappings":";AAEA,qDACiC,OAAE,EAAE,GAAG,WAAI,eAO1C"}
1
+ {"version":3,"file":"setInstruction.d.ts","sourceRoot":"","sources":["../src/setInstruction.js"],"names":[],"mappings":";AAEA,qDAQiC,YAAE,EAAE,GAAG,MAHtB,GAAC,EAGyB,cAO1C"}
@@ -0,0 +1,12 @@
1
+ import { defineConfig } from 'vitest/config'
2
+
3
+ export default defineConfig({
4
+ test: {
5
+ environment: 'node',
6
+ coverage: {
7
+ provider: 'v8',
8
+ reporter: ['lcov', 'text-summary'],
9
+ },
10
+
11
+ },
12
+ })