@peter.naydenov/cuts 1.3.1 → 1.4.1

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/AGENTS.md ADDED
@@ -0,0 +1,48 @@
1
+ # Agent Guidelines for @peter.naydenov/cuts
2
+
3
+ ## Build/Test Commands
4
+ - **Build**: `npm run build` (runs rollup then TypeScript declarations)
5
+ - **Test all**: `npm test` (mocha test-mocha/*.js)
6
+ - **Test coverage**: `npm run cover` (c8 mocha test-mocha/*.js)
7
+ - **Component tests**: `npm run cypress` (opens Cypress component tests)
8
+ - **Dev server**: `npm run dev` (vite dev server)
9
+ - **Preview**: `npm run preview` (vite preview)
10
+
11
+ ## Code Style Guidelines
12
+
13
+ ### File Structure
14
+ - Use ES6 modules with `import`/`export`
15
+ - Add `'use strict'` at the top of all JS files
16
+ - Source files in `src/`, TypeScript declarations generated to `types/`
17
+
18
+ ### Imports & Dependencies
19
+ - Group imports: external libraries first, then local modules
20
+ - Use descriptive import names
21
+ - One import per line for clarity
22
+
23
+ ### Naming Conventions
24
+ - Functions: camelCase (e.g., `findInstructions`, `setInstruction`)
25
+ - Variables: camelCase (e.g., `shortcutMngr`, `currentScene`)
26
+ - Constants: camelCase (e.g., `sceneNames`, `jumpStack`)
27
+ - Files: camelCase with .js extension
28
+
29
+ ### Code Formatting
30
+ - Multi-line variable declarations with trailing commas
31
+ - Consistent indentation (4 spaces)
32
+ - JSDoc comments for all public functions
33
+ - Descriptive variable names over abbreviations
34
+
35
+ ### Error Handling
36
+ - Use logging for errors with structured objects: `{message, level, type}`
37
+ - Return promises for async operations
38
+ - Validate inputs and provide meaningful error messages
39
+
40
+ ### TypeScript
41
+ - Generate .d.ts files from JS source using TypeScript compiler
42
+ - Use JSDoc for type annotations in source code
43
+ - Declaration maps enabled for better IDE support
44
+
45
+ ### Testing
46
+ - Use Mocha for unit tests in `test-mocha/` directory
47
+ - Component tests with Cypress
48
+ - Coverage reporting with c8
package/Changelog.md CHANGED
@@ -1,6 +1,12 @@
1
1
  # Release History
2
2
 
3
3
 
4
+
5
+ ## 1.4.0 ( 2025-09-06)
6
+ - [x] New methods: jump, jumpBack, jumpsReset
7
+
8
+
9
+
4
10
  ## 1.3.1 ( 2025-08-15)
5
11
  - [ ] Fix: Missing typedef for plugin 'form'
6
12
 
package/README.md CHANGED
@@ -46,13 +46,16 @@ script.show ({ scene : 'sceneName'}) // change the current Scene
46
46
  setScenes : 'Provide list of scenes to the app'
47
47
  , show : 'Change the current scene'
48
48
  , hide : 'Hide the current scene'
49
+ , jump : 'Go to the requested scene but remember the current scene'
50
+ , jumpBack : 'Jump back to the scene before the jump'
51
+ , jumpsReset : 'Reset the jump stack'
49
52
  , listScenes : 'List of loaded Scene names'
50
53
  , listShortcuts : 'List shortcuts per Scene. Provide the name of the Scene'
51
54
  , setDependencies : 'Add object to the "dependencies" object. This object will be passed to the Scene "show" method'
52
55
  , getDependencies : 'Returns the "dependencies" object'
53
56
  , enablePlugin : 'Enable a shortcut plugin. Available after version 1.1.0'
54
57
  , disablePlugin : 'Disable a shortcut plugin. Available after version 1.1.0'
55
- , emit : 'Emit an event. Available after version 2.0.0'
58
+ , emit : 'Emit an event'
56
59
  ```
57
60
 
58
61
 
@@ -85,6 +88,26 @@ AfterShow and BeforeHide are optional methods that coming after version 1.2.x. `
85
88
  `BeforeHide` is function that will run before navigation away from the scene. It's inspired by the `beforeunload` event. Here we can write code that will prevent navigation away from the scene. Should return a boolean. If true, navigation will be allowed, if false, navigation will be prevented.
86
89
 
87
90
 
91
+ ## Jump, JumpBack and JumpsReset methods
92
+
93
+ Jump and JumpBack are created to simplify scene navigation flow. `Jump` will change the current scene as show method, but will remember the current scene as a point to return. `JumpBack` will go back to the scene before the jump. You can have multiple jumps. All scene names are recorded in the jump stack and you can getback to any scene in the stack. `JumpsReset` will reset the memory of the jump stack.
94
+
95
+ ```js
96
+ script.show ({ scene : 'test' }) // Will load the 'test' scene. No memory
97
+ script.jump ({ scene : 'blue' }) // Will load the 'blue' scene. Will remember 'test' scene in the jump stack
98
+ script.jump ({ scene : 'green' }) // Will load the 'green' scene. Will remember 'blue' scene in the jump stack
99
+
100
+ script.jumpBack () // Will load scene from the jump stack. Will load 'blue' scene
101
+ script.jumpBack () // Will load scene from the jump stack. Will load 'test' scene
102
+ script.jumpBack () // Will do nothing. No more scenes in the jump stack
103
+
104
+ // Let's imagine that we made some jumps already. Our jumpStack is ['test', 'blue']
105
+ // If we want to go back few steps back, we can use the 'hops' parameter
106
+ script.jumpBack ({hops:2}) // Will load scene from the jump stack. Will load 'test' scene
107
+ // Default value for the 'hops' parameter is 1
108
+ ```
109
+
110
+
88
111
 
89
112
  ## Links
90
113
  - [History of changes](https://github.com/PeterNaydenov/cuts/blob/main/Changelog.md)
package/dist/cuts.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";var e=require("@peter.naydenov/shortcuts"),n=require("ask-for-promise"),r=require("@peter.naydenov/log");function*t(e,n,r,t){let s=null;if(null===e)return yield*t.map((e=>[e,"show"])),void(yield[r,"show"]);if(!t||0===t.length)return n?(yield[e,"hide"],n.reverse(),yield*n.map((e=>[e,"hide"])),void(yield[r,"show"])):(yield[e,"hide"],void(yield[r,"show"]));if(t.includes(e)){for(let n=t.indexOf(e)+1;n<t.length;n++)yield[t[n],"show"];yield[r,"show"]}else{if(!n)return yield[e,"hide"],void(yield*t.map((e=>[e,"show"])));if(t.every(((e,r)=>n[r]===t[r]&&(s=r,!0))),null==s)return yield[e,"hide"],n.reverse(),yield*n.map((e=>[e,"hide"])),yield*t.map((e=>[e,"show"])),void(yield[r,"show"]);yield[e,"hide"];for(let e=n.length;e>s+1;e--)yield[n[e-1],"hide"];for(let e=s+1;e<t.length;e++)yield[t[e],"show"];yield[r,"show"]}}function s(e){return function(n,...r){const{askForPromise:t,deps:s}=e;return function(){const e=t();return n({task:e,dependencies:s()},...r),e.promise}}}function o(e,n){return function(e){const{scenes:r,sceneNames:t}=n;if(!t.has(e))return null;const{show:s,hide:o,parents:i,beforeUnload:c,afterLoad:u,...l}=r[e];return Object.keys(l)}}module.exports=function(i={logLevel:0}){const c=e.shortcuts(),u=i.logLevel||0,l=r({level:u}),d={currentScene:null,currentParents:null,sceneNames:new Set,scenes:{},opened:!1},a={},p={shortcutMngr:c,findInstructions:t,askForPromise:n,setInstruction:s({askForPromise:n,deps:c.getDependencies}),log:l};return a.hide=function(e,n){return function(r=1){const{askForPromise:t,shortcutMngr:s,setInstruction:o}=e,{currentScene:i,currentParents:c,scenes:u}=n,l=t(),d=[],a=c.length>0;let p;return s.pause(),d.push(o(u[i].hide)),a||(n.currentScene=null),a&&"*"===r&&[...c].reverse().forEach((e=>{p=n.currentParents.pop(),n.currentScene=p,d.push(o(u[e].hide))})),a&&!["*",1].includes(r)&&c.slice("-"+(r-1)).reverse().map((e=>{p=n.currentParents.pop(),n.currentScene=p,d.push(o(u[e].hide))})),(r=t.sequence(d)).onComplete((()=>{s.changeContext(n.currentScene),l.done()})),l.promise}}(p,d),a.listShortcuts=o(0,d),a.listShortcuts=o(0,d),a.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:i,parents:c,...u}=s,l={};l[r]=u,t.load(l)}))}}(p,d),a.show=function(e,n){return function({scene:r,options:t={ssr:!1}},...s){const{shortcutMngr:o,askForPromise:i,log:c,findInstructions:u,setInstruction:l}=e,d=i(),a=i(),{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 d.done(),d.promise;if(!f.has(r)&&c)return c({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.push(n.currentScene),n.currentScene=e;else{let e=n.currentParents.pop();n.currentScene=e}return h[e][r]}m.forEach((e=>f.has(e))),n.currentParents||(n.currentParents=[]);const y=u(n.currentScene,n.currentParents,r,m),P=[];for(let e of y)[e].map(g).map((e=>P.push(l(e),...s)));i.sequence(P).onComplete((()=>{n.opened=!0,o.changeContext(r),"function"==typeof h[r].afterShow&&h[r].afterShow({dependencies:o.getDependencies(),done:()=>{}}),d.done()}))})),d.promise}}(p,d),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.shortcuts.setNote(n),a.listScenes=()=>[...d.sceneNames],a.enablePlugin=(e,n)=>c.enablePlugin(e,n),a.disablePlugin=e=>c.disablePlugin(e),a.emit=(e,...n)=>c.emit(e,...n),a};
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"];yield[t,"show"]}else{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}),l={currentScene:null,currentParents:null,sceneNames:new Set,scenes:{},opened:!1,jumpStack:[]},d={},a={shortcutMngr:c,findInstructions:r,askForPromise:n,setInstruction:s({askForPromise:n,deps:c.getDependencies}),log:u};return d.hide=function(e,n){return function(t=1){const{askForPromise:r,shortcutMngr:s,setInstruction:o}=e,{currentScene:c,currentParents:i,scenes:u}=n,l=r(),d=[],a=i.length>0;let p;return s.pause(),d.push(o(u[c].hide)),a||(n.currentScene=null),a&&"*"===t&&[...i].reverse().forEach((e=>{p=n.currentParents.pop(),n.currentScene=p,d.push(o(u[e].hide))})),a&&!["*",1].includes(t)&&i.slice("-"+(t-1)).reverse().map((e=>{p=n.currentParents.pop(),n.currentScene=p,d.push(o(u[e].hide))})),(t=r.sequence(d)).onComplete((()=>{s.changeContext(n.currentScene),l.done()})),l.promise}}(a,l),d.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,...l}=t[e];return Object.keys(l)}}(0,l),d.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,l={};l[t]=u,r.load(l)}))}}(a,l),d.show=function(e,n){return function({scene:t,options:r={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,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 d.done(),d.promise;if(!f.has(t)&&i)return i({message:`Scene ${t} is not available.`,level:1,type:"error"}),d.done(),d.promise;if(!p&&r.ssr)return n.opened=!0,n.currentPage=t,o.changeContext(t),d.done(),d.promise;const{show:a,parents:m=[]}=h[t];if("*"===m[0])return a().then((()=>d.done())),n.currentParents.push(n.currentPage),n.currentPage=t,d.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(l(e),...s)));c.sequence(S).onComplete((()=>{n.opened=!0,o.changeContext(t),"function"==typeof h[t].afterShow&&h[t].afterShow({dependencies:o.getDependencies(),done:()=>{}}),d.done()}))})),d.promise}}(a,l),d.jump=function(e,n){return function({scene:t},...r){return e.jumpStack.push(e.currentScene),n({scene:t},...r)}}(l,d.show),d.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)}}(l,d.show),d.jumpsReset=function(e){return function(){e.jumpStack=[]}}(l),d.loadPlugins=async function(e){const n=e.map((e=>`plugin${e}`)),t=await import("@peter.naydenov/shortcuts");return n.map((e=>t[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.emit=(e,...n)=>c.emit(e,...n),d};
package/dist/cuts.esm.mjs CHANGED
@@ -1 +1 @@
1
- import{shortcuts as e}from"@peter.naydenov/shortcuts";import n from"ask-for-promise";import r from"@peter.naydenov/log";function*t(e,n,r,t){let s=null;if(null===e)return yield*t.map((e=>[e,"show"])),void(yield[r,"show"]);if(!t||0===t.length)return n?(yield[e,"hide"],n.reverse(),yield*n.map((e=>[e,"hide"])),void(yield[r,"show"])):(yield[e,"hide"],void(yield[r,"show"]));if(t.includes(e)){for(let n=t.indexOf(e)+1;n<t.length;n++)yield[t[n],"show"];yield[r,"show"]}else{if(!n)return yield[e,"hide"],void(yield*t.map((e=>[e,"show"])));if(t.every(((e,r)=>n[r]===t[r]&&(s=r,!0))),null==s)return yield[e,"hide"],n.reverse(),yield*n.map((e=>[e,"hide"])),yield*t.map((e=>[e,"show"])),void(yield[r,"show"]);yield[e,"hide"];for(let e=n.length;e>s+1;e--)yield[n[e-1],"hide"];for(let e=s+1;e<t.length;e++)yield[t[e],"show"];yield[r,"show"]}}function s(e){return function(n,...r){const{askForPromise:t,deps:s}=e;return function(){const e=t();return n({task:e,dependencies:s()},...r),e.promise}}}function o(e,n){return function(e){const{scenes:r,sceneNames:t}=n;if(!t.has(e))return null;const{show:s,hide:o,parents:i,beforeUnload:c,afterLoad:u,...l}=r[e];return Object.keys(l)}}function i(i={logLevel:0}){const c=e(),u=i.logLevel||0,l=r({level:u}),d={currentScene:null,currentParents:null,sceneNames:new Set,scenes:{},opened:!1},a={},p={shortcutMngr:c,findInstructions:t,askForPromise:n,setInstruction:s({askForPromise:n,deps:c.getDependencies}),log:l};return a.hide=function(e,n){return function(r=1){const{askForPromise:t,shortcutMngr:s,setInstruction:o}=e,{currentScene:i,currentParents:c,scenes:u}=n,l=t(),d=[],a=c.length>0;let p;return s.pause(),d.push(o(u[i].hide)),a||(n.currentScene=null),a&&"*"===r&&[...c].reverse().forEach((e=>{p=n.currentParents.pop(),n.currentScene=p,d.push(o(u[e].hide))})),a&&!["*",1].includes(r)&&c.slice("-"+(r-1)).reverse().map((e=>{p=n.currentParents.pop(),n.currentScene=p,d.push(o(u[e].hide))})),(r=t.sequence(d)).onComplete((()=>{s.changeContext(n.currentScene),l.done()})),l.promise}}(p,d),a.listShortcuts=o(0,d),a.listShortcuts=o(0,d),a.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:i,parents:c,...u}=s,l={};l[r]=u,t.load(l)}))}}(p,d),a.show=function(e,n){return function({scene:r,options:t={ssr:!1}},...s){const{shortcutMngr:o,askForPromise:i,log:c,findInstructions:u,setInstruction:l}=e,d=i(),a=i(),{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 d.done(),d.promise;if(!f.has(r)&&c)return c({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.push(n.currentScene),n.currentScene=e;else{let e=n.currentParents.pop();n.currentScene=e}return h[e][r]}m.forEach((e=>f.has(e))),n.currentParents||(n.currentParents=[]);const y=u(n.currentScene,n.currentParents,r,m),P=[];for(let e of y)[e].map(g).map((e=>P.push(l(e),...s)));i.sequence(P).onComplete((()=>{n.opened=!0,o.changeContext(r),"function"==typeof h[r].afterShow&&h[r].afterShow({dependencies:o.getDependencies(),done:()=>{}}),d.done()}))})),d.promise}}(p,d),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=()=>[...d.sceneNames],a.enablePlugin=(e,n)=>c.enablePlugin(e,n),a.disablePlugin=e=>c.disablePlugin(e),a.emit=(e,...n)=>c.emit(e,...n),a}export{i as default};
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"];yield[t,"show"]}else{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}),l={currentScene:null,currentParents:null,sceneNames:new Set,scenes:{},opened:!1,jumpStack:[]},d={},a={shortcutMngr:c,findInstructions:r,askForPromise:n,setInstruction:s({askForPromise:n,deps:c.getDependencies}),log:u};return d.hide=function(e,n){return function(t=1){const{askForPromise:r,shortcutMngr:s,setInstruction:o}=e,{currentScene:c,currentParents:i,scenes:u}=n,l=r(),d=[],a=i.length>0;let p;return s.pause(),d.push(o(u[c].hide)),a||(n.currentScene=null),a&&"*"===t&&[...i].reverse().forEach((e=>{p=n.currentParents.pop(),n.currentScene=p,d.push(o(u[e].hide))})),a&&!["*",1].includes(t)&&i.slice("-"+(t-1)).reverse().map((e=>{p=n.currentParents.pop(),n.currentScene=p,d.push(o(u[e].hide))})),(t=r.sequence(d)).onComplete((()=>{s.changeContext(n.currentScene),l.done()})),l.promise}}(a,l),d.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,...l}=t[e];return Object.keys(l)}}(0,l),d.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,l={};l[t]=u,r.load(l)}))}}(a,l),d.show=function(e,n){return function({scene:t,options:r={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,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 d.done(),d.promise;if(!f.has(t)&&i)return i({message:`Scene ${t} is not available.`,level:1,type:"error"}),d.done(),d.promise;if(!p&&r.ssr)return n.opened=!0,n.currentPage=t,o.changeContext(t),d.done(),d.promise;const{show:a,parents:m=[]}=h[t];if("*"===m[0])return a().then((()=>d.done())),n.currentParents.push(n.currentPage),n.currentPage=t,d.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(l(e),...s)));c.sequence(S).onComplete((()=>{n.opened=!0,o.changeContext(t),"function"==typeof h[t].afterShow&&h[t].afterShow({dependencies:o.getDependencies(),done:()=>{}}),d.done()}))})),d.promise}}(a,l),d.jump=function(e,n){return function({scene:t},...r){return e.jumpStack.push(e.currentScene),n({scene:t},...r)}}(l,d.show),d.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)}}(l,d.show),d.jumpsReset=function(e){return function(){e.jumpStack=[]}}(l),d.loadPlugins=async function(e){const n=e.map((e=>`plugin${e}`)),t=await import("@peter.naydenov/shortcuts");return n.map((e=>t[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.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=e.code.replace("Key","").replace("Digit",""),i=[];return r&&i.push("CTRL"),n&&i.push("SHIFT"),o&&i.push("ALT"),t.hasOwnProperty(s)?i.push(t[s].toUpperCase()):["ControlLeft","ControlRight","ShiftLeft","ShiftRight","AltLeft","AltRight","Meta"].includes(s)||i.push(s.toUpperCase()),i.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 d=u.map((e=>e())).reduce(((e,t)=>(e.push(t),e)),[]);return t.watchList=document.querySelectorAll(d),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 d(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)n.add(o);else{const o=Object.keys(e),r=Object.keys(t);n=new Set([...r,...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 d=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,d=null,m=0;function p(){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,d=null,l=null,a=null,m=0}function h(n){let r=i.maxClicks;return clearTimeout(f),d?(clearTimeout(d),void(d=setTimeout((()=>d=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?(p(),void(r>1&&(d=setTimeout((()=>d=null),u)))):void(f=setTimeout(p,u)))}function g(n){let r=i.maxClicks;return clearTimeout(f),d?(clearTimeout(d),void(d=setTimeout((()=>d=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?(p(),void(r>1&&(d=setTimeout((()=>d=null),u)))):void(f=setTimeout(p,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&&d.start();let p={getPrefix:()=>"click",shortcutName:e=>i(e),contextChange:()=>{m=u(a,f),m<1&&d.stop(),m>0&&d.start()},mute:()=>d.stop(),unmute:()=>d.start(),destroy:()=>{d.stop(),f=null,p=null}};return Object.freeze(p),p},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 d={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,d=null}};return Object.freeze(d),d},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},d={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,d=!0,m=!1;const p=()=>d=!1,h=()=>d=!0,g=()=>m=!0,y=()=>!1===d;function v(){let e=a.map((e=>[e.join("+")]));const t={wait:p,end:h,ignore:g,isWaiting:y,note:i.note,context:i.name,dependencies:s.extra,type:"key"};if(!d){let o=e.at(-1);n.emit(o,t),m&&(e=e.slice(0,-1),m=!1)}if(d){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))):d&&a.length===u.maxSequence?(v(),void(u.keyIgnore=setTimeout((()=>u.keyIgnore=null),l))):void(d?f=setTimeout(v,l):v())}function C(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)),d&&a.length===u.maxSequence)return v(),void(u.keyIgnore=setTimeout((()=>u.keyIgnore=null),l));d?f=setTimeout(v,l):v()}}return{start:function(){t.active||(document.addEventListener("keydown",x),document.addEventListener("keypress",C),t.active=!0)},stop:function(){t.active&&(document.removeEventListener("keydown",x),document.removeEventListener("keypress",C),t.active=!1)}}}(f,d),p=o(f,d);p>0&&m.start();let h={getPrefix:()=>"key",shortcutName:e=>t(e),contextChange:e=>{p=o(f,d),p<1&&m.stop(),p>0&&m.start()},mute:()=>m.stop(),unmute:()=>m.start(),destroy:()=>{m.stop(),d=null,h=null}};return Object.freeze(h),h},shortcuts:d});function p(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*C(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"];yield[n,"show"]}else{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 k(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}}}function P(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)}}return p.sequence=function(e,...t){const n=p(),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},p.all=function(e,...t){const n=p(),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=d(),n=x({level:e.logLevel||0}),o={currentScene:null,currentParents:null,sceneNames:new Set,scenes:{},opened:!1},r={},s={shortcutMngr:t,findInstructions:C,askForPromise:p,setInstruction:k({askForPromise:p,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 d;return r.pause(),a.push(s(u[i].hide)),f||(t.currentScene=null),f&&"*"===n&&[...c].reverse().forEach((e=>{d=t.currentParents.pop(),t.currentScene=d,a.push(s(u[e].hide))})),f&&!["*",1].includes(n)&&c.slice("-"+(n-1)).reverse().map((e=>{d=t.currentParents.pop(),t.currentScene=d,a.push(s(u[e].hide))})),(n=o.sequence(a)).onComplete((()=>{r.changeContext(t.currentScene),l.done()})),l.promise}}(s,o),r.listShortcuts=P(0,o),r.listShortcuts=P(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:d,scenes:m,sceneNames:p,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(!p.has(n)&&c)return c({message:`Scene ${n} is not available.`,level:1,type:"error"}),a.done(),a.promise;if(!d&&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=>p.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.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=>d.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((([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=e.code.replace("Key","").replace("Digit",""),i=[];return r&&i.push("CTRL"),n&&i.push("SHIFT"),o&&i.push("ALT"),t.hasOwnProperty(s)?i.push(t[s].toUpperCase()):["ControlLeft","ControlRight","ShiftLeft","ShiftRight","AltLeft","AltRight","Meta"].includes(s)||i.push(s.toUpperCase()),i.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)n.add(o);else{const o=Object.keys(e),r=Object.keys(t);n=new Set([...r,...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"];yield[n,"show"]}else{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}}));
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.3.1",
4
+ "version": "1.4.1",
5
5
  "license": "MIT",
6
6
  "author": "Peter Naydenov",
7
7
  "main": "./src/main.js",
@@ -22,7 +22,7 @@
22
22
  "build": "rollup -c",
23
23
  "postbuild": "tsc -p tsconfig.json",
24
24
  "preview": "vite preview",
25
- "test": "mocha test-mocha/*.js",
25
+ "test": "mocha ./test-mocha/*.js",
26
26
  "cover": "c8 mocha test-mocha/*.js",
27
27
  "cypress": "cypress open --component --browser chrome"
28
28
  },
@@ -35,16 +35,16 @@
35
35
  "@rollup/plugin-commonjs": "^28.0.6",
36
36
  "@rollup/plugin-node-resolve": "^16.0.1",
37
37
  "@rollup/plugin-terser": "^0.4.4",
38
- "@types/node": "^24.2.1",
38
+ "@types/node": "^24.5.2",
39
39
  "@vitejs/plugin-vue": "^6.0.1",
40
40
  "c8": "^10.1.3",
41
- "chai": "^5.2.1",
42
- "cypress": "^14.5.4",
43
- "mocha": "^11.7.1",
44
- "rollup": "^4.46.2",
41
+ "chai": "^6.0.1",
42
+ "cypress": "^15.3.0",
43
+ "mocha": "^11.7.2",
44
+ "rollup": "^4.52.2",
45
45
  "typescript": "^5.9.2",
46
- "vite": "^7.1.2",
47
- "vue": "^3.5.18"
46
+ "vite": "^7.1.7",
47
+ "vue": "^3.5.21"
48
48
  },
49
49
  "dependencies": {
50
50
  "@peter.naydenov/log": "^1.1.1",
package/src/main.js CHANGED
@@ -29,7 +29,9 @@ import hide from './methods/hide.js'
29
29
  import listShortcuts from './methods/listShortcuts.js'
30
30
  import setScenes from './methods/setScenes.js'
31
31
  import show from './methods/show.js'
32
-
32
+ import jump from './methods/jump.js'
33
+ import jumpBack from './methods/jumpBack.js'
34
+ import jumpsReset from './methods/jumpsReset.js'
33
35
 
34
36
 
35
37
  function main ( cfg= {logLevel:0} ) {
@@ -43,6 +45,7 @@ function main ( cfg= {logLevel:0} ) {
43
45
  , sceneNames : new Set () // Set with all loaded scenes;
44
46
  , scenes : {} // Collection of all scenes;
45
47
  , opened : false // Flag to indicate if the scene manager is opened
48
+ , jumpStack : [] // Stack of jump instructions
46
49
  }
47
50
  , API = {}
48
51
  , inAPI = {}
@@ -59,15 +62,17 @@ function main ( cfg= {logLevel:0} ) {
59
62
 
60
63
  API.hide = hide ( dependencies, state )
61
64
  API.listShortcuts = listShortcuts ( dependencies, state )
62
- API.listShortcuts = listShortcuts ( dependencies, state )
63
65
  API.setScenes = setScenes ( dependencies, state )
64
66
  API.show = show ( dependencies, state )
67
+ API.jump = jump ( state, API.show )
68
+ API.jumpBack = jumpBack ( state, API.show )
69
+ API.jumpsReset = jumpsReset ( state )
65
70
 
66
71
  /**
67
72
  * @typedef {'Key'|'Click'|'Form' } pluginNames
68
- * @description List of possible plugin names: 'Key', 'Click'
73
+ * @description List of possible plugin names: 'Key', 'Click', 'Form'
69
74
  *
70
- * Load a needed shortcut plugins - 'Key', 'Click' or both.
75
+ * Load a needed shortcut plugins - 'Key', 'Click', 'Form' and so on.
71
76
  * It's a async function. Don't forget to 'await' it.
72
77
  * @function loadPlugins
73
78
  * @param {Array.<pluginNames>} plugins - list of plugins to load
@@ -0,0 +1,13 @@
1
+ function jump ( state, show ) {
2
+ function jump ( { scene }, ...args ) {
3
+ state.jumpStack.push ( state.currentScene )
4
+ return show ( { scene }, ...args )
5
+ }
6
+ return jump
7
+ } // jump func.
8
+
9
+
10
+
11
+ export default jump
12
+
13
+
@@ -0,0 +1,16 @@
1
+ function jumpBack ( state, show ) {
2
+ function jumpBack ({hops}={hops:1}, ...args ) {
3
+ for ( let i = 0; i < hops-1; i++ ) {
4
+ state.jumpStack.pop ()
5
+ }
6
+ if ( state.jumpStack.length === 0 ) return
7
+ const lastScene = state.jumpStack.pop ();
8
+ return show ( { scene : lastScene }, ...args )
9
+ }
10
+ return jumpBack
11
+ } // jumpBack func.
12
+
13
+
14
+ export default jumpBack
15
+
16
+
@@ -0,0 +1,11 @@
1
+ function jumpsReset ( state ) {
2
+ return function jumpReset () {
3
+ state.jumpStack = []
4
+ }
5
+ } // jumpsReset func.
6
+
7
+
8
+
9
+ export default jumpsReset
10
+
11
+
@@ -42,7 +42,7 @@ function show ( dependencies, state ) {
42
42
  if ( !sceneNames.has ( requestedScene ) ) {
43
43
  if ( log ) {
44
44
  log ({
45
- message: `Scene ${requestedScene} is not available.`
45
+ message: `Scene ${requestedScene} is not available.`
46
46
  , level : 1
47
47
  , type : 'error'
48
48
  })
package/types/main.d.ts CHANGED
@@ -11,6 +11,13 @@ declare function main(cfg?: {
11
11
  ssr: boolean;
12
12
  };
13
13
  }, ...args?: any[]) => Promise<any>;
14
+ jump: ({ scene }: {
15
+ scene: any;
16
+ }, ...args: any[]) => any;
17
+ jumpBack: ({ hops }?: {
18
+ hops: number;
19
+ }, ...args: any[]) => any;
20
+ jumpsReset: () => void;
14
21
  loadPlugins(plugins: Array<"Key" | "Click" | "Form">): Promise<Function[]>;
15
22
  setDependencies(deps: any): any;
16
23
  getDependencies(): any;
@@ -1 +1 @@
1
- {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.js"],"names":[],"mappings":";AAkCA;;;;;sBAdmB,gBAAgB;;;;;;;yBAoDhB,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;;;;;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"}
@@ -0,0 +1,5 @@
1
+ export default jump;
2
+ declare function jump(state: any, show: any): ({ scene }: {
3
+ scene: any;
4
+ }, ...args: any[]) => any;
5
+ //# sourceMappingURL=jump.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jump.d.ts","sourceRoot":"","sources":["../../src/methods/jump.js"],"names":[],"mappings":";AAAA;;0BAMC"}
@@ -0,0 +1,5 @@
1
+ export default jumpBack;
2
+ declare function jumpBack(state: any, show: any): ({ hops }?: {
3
+ hops: number;
4
+ }, ...args: any[]) => any;
5
+ //# sourceMappingURL=jumpBack.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jumpBack.d.ts","sourceRoot":"","sources":["../../src/methods/jumpBack.js"],"names":[],"mappings":";AAAA;;0BAUC"}
@@ -0,0 +1,3 @@
1
+ export default jumpsReset;
2
+ declare function jumpsReset(state: any): () => void;
3
+ //# sourceMappingURL=jumpsReset.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jumpsReset.d.ts","sourceRoot":"","sources":["../../src/methods/jumpsReset.js"],"names":[],"mappings":";AAAA,oDAIC"}