@peter.naydenov/cuts 2.1.3 → 2.1.5
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 +28 -0
- package/README.md +1 -1
- package/coverage/lcov-report/index.html +29 -29
- package/coverage/lcov-report/src/findInstructions.js.html +27 -27
- package/coverage/lcov-report/src/index.html +25 -25
- package/coverage/lcov-report/src/main.js.html +129 -51
- package/coverage/lcov-report/src/methods/hide.js.html +127 -67
- package/coverage/lcov-report/src/methods/index.html +38 -38
- package/coverage/lcov-report/src/methods/jump.js.html +27 -12
- package/coverage/lcov-report/src/methods/jumpBack.js.html +10 -10
- package/coverage/lcov-report/src/methods/jumpsReset.js.html +3 -3
- package/coverage/lcov-report/src/methods/listShortcuts.js.html +5 -5
- package/coverage/lcov-report/src/methods/setScenes.js.html +16 -16
- package/coverage/lcov-report/src/methods/show.js.html +154 -76
- package/coverage/lcov-report/src/setInstruction.js.html +23 -11
- package/coverage/lcov.info +362 -314
- package/dist/cuts.cjs +1 -1
- package/dist/cuts.esm.mjs +1 -1
- package/dist/cuts.umd.js +1 -1
- package/package.json +2 -2
- package/src/main.js +28 -9
- package/src/methods/hide.js +46 -39
- package/src/methods/jump.js +7 -2
- package/src/methods/jumpBack.js +2 -2
- package/src/methods/jumpsReset.js +1 -1
- package/src/methods/setScenes.js +1 -1
- package/src/methods/show.js +23 -6
- package/src/setInstruction.js +5 -1
- package/test/02-cuts.test.js +339 -1
- package/types/main.d.ts +42 -6
- package/types/main.d.ts.map +1 -1
- package/types/methods/hide.d.ts +1 -1
- package/types/methods/hide.d.ts.map +1 -1
- package/types/methods/jump.d.ts.map +1 -1
- package/types/methods/setScenes.d.ts +2 -2
- package/types/methods/show.d.ts.map +1 -1
- package/types/setInstruction.d.ts.map +1 -1
- package/vitest.config.js +1 -1
package/dist/cuts.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var e=require("@peter.naydenov/shortcuts"),n=require("ask-for-promise"),
|
|
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,o=!0;if(null===e)return yield*r.map(e=>[e,"show"]),void(yield[t,"show"]);if(0!==r.length){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"]}else{if(yield[e,"hide"],n.includes(t)){let e=n.indexOf(t),r=n.filter((n,t)=>t>e);r.reverse(),yield*r.map(e=>[e,"hide"]),o=!1}else{let e=[...n];e.reverse(),yield*e.map(e=>[e,"hide"])}o&&(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.catch(()=>{})}}}module.exports=function(o={}){const c=e.shortcuts({errorEventName:"@app-error"}),i=o.logLevel??1,u=t({level:i},e=>{const{type:n,logLevel:t}=e;0!==t&&"error"===n&&c.getDependencies().emit("@app-error",e)}),d={currentScene:null,currentParents:null,sceneNames:new Set,scenes:{},opened:!1,jumpStack:[]},l={},p={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,scenes:i}=n,u=r(),d=r();if("function"==typeof i[c].beforeHide){const e=i[c].beforeHide;try{const n=e({done:d.done,dependencies:s.getDependencies()});null!=n&&"function"==typeof n.then&&n.then(d.done).catch(()=>d.done(!1))}catch(e){d.done(!1)}}else d.done(!0);return d.onComplete(e=>{if(!e)return u.done(),u.promise;const d=[],l=[...n.currentParents];s.pause(),d.push(o(i[c].hide));const p="*"===t?l.length:Math.min(t-1,l.length);for(let e=0;e<p;e++){const e=l.pop();d.push(o(i[e].hide))}n.currentScene=l.length>0?l.pop():null,n.currentParents=l,r.sequence(d).onComplete(()=>{s.changeContext(n.currentScene),u.done()})}),u.promise}}(p,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,beforeHide:i,afterShow:u,...d}=t[e];return Object.keys(d)}}(0,d),l.setScenes=function(e,n){return function(t){const{shortcutMngr:r,log:s}=e;t.forEach(e=>{if(null==e)return;const{name:t,scene:o}=e;if(!t)return void s({message:"Scene name is not defined",level:1,type:"error"});if(null==o)return void s({message:`Scene ${t} is not defined`,level:1,type:"error"});o.parents||(o.parents=[]),n.scenes[t]=o,n.sceneNames.add(t);const{show:c,hide:i,parents:u,...d}=o,l={};l[t]=d,r.load(l)})}}(p,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(),p=c(),{opened:a,scenes:h,sceneNames:f,currentScene:m}=n;if(m&&"function"==typeof h[m].beforeHide){const e=h[m].beforeHide;try{const n=e({done:p.done,dependencies:o.getDependencies()});null!=n&&"function"==typeof n.then&&n.then(p.done).catch(()=>p.done(!1))}catch(e){p.done(!1)}}else p.done(!0);return p.onComplete(e=>{if(!e)return l.done(),l.promise;if(!f.has(t))return i({message:`Scene "${t}" is not available.`,level:1,type:"error"}),l.done(),l.promise;if(!a&&r.ssr)return n.opened=!0,n.currentScene=t,n.currentParents=h[t].parents?[...h[t].parents]:[],o.changeContext(t),l.done(),l.promise;const{show:p,parents:m=[]}=h[t];if(n.currentParents||(n.currentParents=[]),"*"===m[0])return d(p,...s)().then(()=>l.done()),n.currentScene&&n.currentScene!==t&&n.currentParents.push(n.currentScene),n.currentScene=t,o.changeContext(t),l.promise;if(0!==m.length&&!m.every(e=>f.has(e)))return i({message:`Some of '${t}' parent scenes are not set.`,level:1,type:"error"}),l.done(),l.promise;function g([e,t]){if("show"===t)n.currentScene&&(n.currentParents=[...h[n.currentScene].parents]),n.currentScene=e;else{let t="*"===h[e].parents[0]?n.currentParents.pop():h[e].parents.at(-1);n.currentScene=t}return h[e][t]}const y=u(n.currentScene,[...n.currentParents],t,m),S=[];for(let e of y){const n=g(e);S.push(d(n,...s))}c.sequence(S).onComplete(()=>{n.opened=!0,n.currentScene=t,n.currentParents=h[t].parents?[...h[t].parents]:null,o.changeContext(t),"function"==typeof h[t].afterShow&&h[t].afterShow({dependencies:o.getDependencies(),done:()=>{}}),l.done()})}),l.promise}}(p,d),l.jump=function(e,n){return function({scene:t},...r){const s=e.currentScene;return n({scene:t},...r).then(()=>{e.currentScene===t&&e.jumpStack.push(s)}).catch(()=>{})}}(d,l.show),l.jumpBack=function(e,n){return function({hops:t=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).catch(()=>{})}}(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=e=>c.setNote(e),l.listScenes=()=>[...d.sceneNames],l.enablePlugin=(e,n)=>c.enablePlugin(e,n),l.disablePlugin=e=>c.disablePlugin(e),l.getState=()=>({scene:d.currentScene,parents:d.currentParents?[...d.currentParents]:d.currentParents,opened:d.opened}),l.emit=(e,...n)=>c.getDependencies().emit(e,...n),l};
|
package/dist/cuts.esm.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{shortcuts as e}from"@peter.naydenov/shortcuts";import n from"ask-for-promise";import
|
|
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 o=null,s=!0;if(null===e)return yield*r.map(e=>[e,"show"]),void(yield[t,"show"]);if(0!==r.length){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]&&(o=t,!0)),null==o)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>o+1;e--)yield[n[e-1],"hide"];for(let e=o+1;e<r.length;e++)yield[r[e],"show"];yield[t,"show"]}else{if(yield[e,"hide"],n.includes(t)){let e=n.indexOf(t),r=n.filter((n,t)=>t>e);r.reverse(),yield*r.map(e=>[e,"hide"]),s=!1}else{let e=[...n];e.reverse(),yield*e.map(e=>[e,"hide"])}s&&(yield[t,"show"])}}function o(e){return function(n,...t){const{askForPromise:r,deps:o}=e;return function(){const e=r();return n({task:e,dependencies:o()},...t),e.promise.catch(()=>{})}}}function s(s={}){const c=e({errorEventName:"@app-error"}),i=s.logLevel??1,u=t({level:i},e=>{const{type:n,logLevel:t}=e;0!==t&&"error"===n&&c.getDependencies().emit("@app-error",e)}),d={currentScene:null,currentParents:null,sceneNames:new Set,scenes:{},opened:!1,jumpStack:[]},l={},p={shortcutMngr:c,findInstructions:r,askForPromise:n,setInstruction:o({askForPromise:n,deps:c.getDependencies}),log:u};return l.hide=function(e,n){return function(t=1){const{askForPromise:r,shortcutMngr:o,setInstruction:s}=e,{currentScene:c,scenes:i}=n,u=r(),d=r();if("function"==typeof i[c].beforeHide){const e=i[c].beforeHide;try{const n=e({done:d.done,dependencies:o.getDependencies()});null!=n&&"function"==typeof n.then&&n.then(d.done).catch(()=>d.done(!1))}catch(e){d.done(!1)}}else d.done(!0);return d.onComplete(e=>{if(!e)return u.done(),u.promise;const d=[],l=[...n.currentParents];o.pause(),d.push(s(i[c].hide));const p="*"===t?l.length:Math.min(t-1,l.length);for(let e=0;e<p;e++){const e=l.pop();d.push(s(i[e].hide))}n.currentScene=l.length>0?l.pop():null,n.currentParents=l,r.sequence(d).onComplete(()=>{o.changeContext(n.currentScene),u.done()})}),u.promise}}(p,d),l.listShortcuts=function(e,n){return function(e){const{scenes:t,sceneNames:r}=n;if(!r.has(e))return null;const{show:o,hide:s,parents:c,beforeHide:i,afterShow:u,...d}=t[e];return Object.keys(d)}}(0,d),l.setScenes=function(e,n){return function(t){const{shortcutMngr:r,log:o}=e;t.forEach(e=>{if(null==e)return;const{name:t,scene:s}=e;if(!t)return void o({message:"Scene name is not defined",level:1,type:"error"});if(null==s)return void o({message:`Scene ${t} is not defined`,level:1,type:"error"});s.parents||(s.parents=[]),n.scenes[t]=s,n.sceneNames.add(t);const{show:c,hide:i,parents:u,...d}=s,l={};l[t]=d,r.load(l)})}}(p,d),l.show=function(e,n){return function({scene:t,options:r={ssr:!1}},...o){const{shortcutMngr:s,askForPromise:c,log:i,findInstructions:u,setInstruction:d}=e,l=c(),p=c(),{opened:a,scenes:f,sceneNames:h,currentScene:m}=n;if(m&&"function"==typeof f[m].beforeHide){const e=f[m].beforeHide;try{const n=e({done:p.done,dependencies:s.getDependencies()});null!=n&&"function"==typeof n.then&&n.then(p.done).catch(()=>p.done(!1))}catch(e){p.done(!1)}}else p.done(!0);return p.onComplete(e=>{if(!e)return l.done(),l.promise;if(!h.has(t))return i({message:`Scene "${t}" is not available.`,level:1,type:"error"}),l.done(),l.promise;if(!a&&r.ssr)return n.opened=!0,n.currentScene=t,n.currentParents=f[t].parents?[...f[t].parents]:[],s.changeContext(t),l.done(),l.promise;const{show:p,parents:m=[]}=f[t];if(n.currentParents||(n.currentParents=[]),"*"===m[0])return d(p,...o)().then(()=>l.done()),n.currentScene&&n.currentScene!==t&&n.currentParents.push(n.currentScene),n.currentScene=t,s.changeContext(t),l.promise;if(0!==m.length&&!m.every(e=>h.has(e)))return i({message:`Some of '${t}' parent scenes are not set.`,level:1,type:"error"}),l.done(),l.promise;function g([e,t]){if("show"===t)n.currentScene&&(n.currentParents=[...f[n.currentScene].parents]),n.currentScene=e;else{let t="*"===f[e].parents[0]?n.currentParents.pop():f[e].parents.at(-1);n.currentScene=t}return f[e][t]}const y=u(n.currentScene,[...n.currentParents],t,m),S=[];for(let e of y){const n=g(e);S.push(d(n,...o))}c.sequence(S).onComplete(()=>{n.opened=!0,n.currentScene=t,n.currentParents=f[t].parents?[...f[t].parents]:null,s.changeContext(t),"function"==typeof f[t].afterShow&&f[t].afterShow({dependencies:s.getDependencies(),done:()=>{}}),l.done()})}),l.promise}}(p,d),l.jump=function(e,n){return function({scene:t},...r){const o=e.currentScene;return n({scene:t},...r).then(()=>{e.currentScene===t&&e.jumpStack.push(o)}).catch(()=>{})}}(d,l.show),l.jumpBack=function(e,n){return function({hops:t=1}={},...r){for(let n=0;n<t-1;n++)e.jumpStack.pop();if(0===e.jumpStack.length)return;const o=e.jumpStack.pop();return n({scene:o},...r).catch(()=>{})}}(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=e=>c.setNote(e),l.listScenes=()=>[...d.sceneNames],l.enablePlugin=(e,n)=>c.enablePlugin(e,n),l.disablePlugin=e=>c.disablePlugin(e),l.getState=()=>({scene:d.currentScene,parents:d.currentParents?[...d.currentParents]:d.currentParents,opened:d.opened}),l.emit=(e,...n)=>c.getDependencies().emit(e,...n),l}export{s 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 i=e(o);i!==o&&(delete n[t][o],n[t][i]=r)})})}},_readShortcutWithPlugins:function(e,t){return function(n){const{inAPI:o}=e,r=n.split(":")[0].toLowerCase().trim(),i=o._systemAction(r,"none");let s=n;return-1!==i&&(s=t.plugins[i].shortcutName(n)),s}},_setupPlugin:function(e,t){const{inAPI:n}=e,{currentContext:o,shortcuts:r,exposeShortcut:i,ERROR_EVENT_NAME:s}=t;return function(t){const{prefix:c,_normalizeShortcutName:u,_registerShortcutEvents:l,_listenDOM:a,pluginState:p,deps:d}=t,{resetState:f}=d;p.currentContext=o,p.shortcuts=r,p.exposeShortcut=i,p.ERROR_EVENT_NAME=s;const h={ev:e.ev,extra:e.extra,...d};n._normalizeWithPlugins(u);let m=l(h,p);const g=a(h,p);m>0&&g.start();const v={getPrefix:()=>c,shortcutName:e=>u(e),contextChange:()=>{f(),m=l(h,p),m<1&&g.stop(),m>0&&g.start()},mute:()=>g.stop(),unmute:()=>g.start(),destroy:()=>{g.stop(),f()}};return Object.freeze(v),v}},_systemAction:function(e,t){return function(e,n,o=null){return t.plugins.findIndex(t=>t.getPrefix()===e&&(t[n]&&t[n](o),!0))}},changeContext:function(e,t){const{shortcuts:n,currentContext:o,ERROR_EVENT_NAME:r}=t,{ev:i}=e;return function(e=!1){const s=o.name;if(!e)return i.reset(),void(o.name=null);s!==e&&(n[e]?(n[s]&&i.reset(),o.name=e,t.plugins.forEach(t=>t.contextChange(e)),Object.entries(n[e]).forEach(([e,t])=>{e.includes(":SETUP")||t.forEach(t=>i.on(e,t))}),i.on("*",(...e)=>{t.exposeShortcut&&t.exposeShortcut(...e)})):i.emit(r,`Context '${e}' does not exist`))}},listShortcuts:function(e,t){const n=t.shortcuts;return function(e=null){if(null!=e){const t=n[e];return null==t?null:Object.entries(t).map(([e,t])=>e)}return Object.keys(n).map(e=>{const 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:i}}=e;return function(e){const t=i(),s=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 i=t;const c=t.toUpperCase().trim(),u=s.map((e,t)=>c.startsWith(e)?t:null).filter(e=>null!==e);if(u.length){const e=u[0];i=o[e].shortcutName(t)}r instanceof Function&&(r=[r]),n[e][i]=r})}),c&&(r(),r(t))}},unload:function(e,t){const{currentContext:n,shortcuts:o,ERROR_EVENT_NAME:r}=t,{ev:i}=e;return function(e){n.name!==e?o[e]?delete o[e]:i.emit(r,`Context '${e}' does not exist`):i.emit(r,`Context '${e}' can't be removed during is current active context. Change the context first`)}}};function t(e,t){const{ev:n,_specialChars:o,_readKeyEvent:r,extra:i,resetState:s}=e,{currentContext:c,streamKeys:u,listenOptions:l}=t;let a=[],p=null,d=!0,f=!1;const h=()=>d=!1,m=()=>d=!0,g=()=>f=!0,v=()=>!1===d;function y(){const e=a.map(e=>[e.join("+")]),o={wait:h,end:m,ignore:g,isWaiting:v,note:c.note,context:c.name,dependencies:i,options:t.listenOptions,viewport:{X:window.scrollX,Y:window.scrollY,width:window.innerWidth,height:window.innerHeight},type:"key"};if(!d){const t=`KEY:${e.at(-1).join("+")}`;n.emit(t,o),f&&(a=a.slice(0,-1),f=!1)}if(d){const r=`KEY:${e.join(",")}`;n.emit(r,o),f&&(a=a.slice(0,-1),f=!1),a=[],clearTimeout(t.keyIgnore),t.keyIgnore=null,clearTimeout(p),p=null}}function w(n){if(clearTimeout(p),o().hasOwnProperty(n.code))return a.push(r(n,o)),u&&u({key:n.key,context:c.name,note:c.note,dependencies:e.extra}),t.keyIgnore?(clearTimeout(t.keyIgnore),t.keyIgnore=setTimeout(()=>t.keyIgnore=null,l.keyWait),void a.pop()):d&&a.length===t.maxSequence?(y(),void(t.keyIgnore=setTimeout(()=>t.keyIgnore=null,l.keyWait))):void(d?p=setTimeout(y,l.keyWait):y())}function x(n){if(!o().hasOwnProperty(n.code)){if(clearTimeout(p),u&&u({key:n.key,context:c.name,note:c.note,dependencies:e.extra}),t.keyIgnore)return clearTimeout(t.keyIgnore),void(t.keyIgnore=setTimeout(()=>t.keyIgnore=null,l.keyWait));if(a.push(r(n,o)),d&&a.length===t.maxSequence)return y(),void(t.keyIgnore=setTimeout(()=>t.keyIgnore=null,l.keyWait));d?p=setTimeout(y,l.keyWait):y()}}return{start:function(){t.active||(document.addEventListener("keydown",w),document.addEventListener("keypress",x),t.active=!0)},stop:function(){t.active&&(document.removeEventListener("keydown",w),document.removeEventListener("keypress",x),t.active=!1,p&&(clearTimeout(p),p=null),t.keyIgnore&&(clearTimeout(t.keyIgnore),t.keyIgnore=null),a=[],d=!0,f=!1)}}}function n(e){const t=e.toUpperCase(),n=/KEY\s*\:/i.test(t),o=t.indexOf(":");return n?t.includes("SETUP")?"KEY:SETUP":`KEY:${t.slice(o+1).split(",").map(e=>e.trim()).map(e=>e.split("+").map(e=>e.trim()).sort().join("+")).join(",")}`:e}function o(e,t){const{shiftKey:n,altKey:o,ctrlKey:r}=e,i=t(),s=e.code.replace("Key","").replace("Digit",""),c=[];return r&&c.push("CTRL"),n&&c.push("SHIFT"),o&&c.push("ALT"),i.hasOwnProperty(s)?c.push(i[s].toUpperCase()):["ControlLeft","ControlRight","ShiftLeft","ShiftRight","AltLeft","AltRight","Meta"].includes(s)||c.push(s.toUpperCase()),c.sort()}function r(e,t){let n=0,o=!1;const r=t.defaultOptions,{regex:i}=e,{currentContext:{name:s},shortcuts:c}=t;return null==s?0:(Object.entries(c[s]).forEach(([s,c])=>{if(!i.test(s))return;if("KEY:SETUP"===s){o=!0;const n=c.reduce((n,o)=>{const r=o({dependencies:e.extra,defaults:structuredClone(t.defaultOptions),options:t.listenOptions});return Object.assign(n,r)},r);return void Object.assign(t.listenOptions,n)}n++;const u=s.slice(4).split(",").length;t.maxSequence<u&&(t.maxSequence=u)}),o||Object.assign(t.listenOptions,r),n)}function i(){return{ArrowLeft:"LEFT",ArrowUp:"UP",ArrowRight:"RIGHT",ArrowDown:"DOWN",Enter:"ENTER",NumpadEnter:"ENTER",Escape:"ESC",Backspace:"BACKSPACE",Space:"SPACE",Tab:"TAB",Backquote:"`",BracketLeft:"[",BracketRight:"]",Equal:"=",Slash:"/",Backslash:"\\",IntlBackslash:"`",F1:"F1",F2:"F2",F3:"F3",F4:"F4",F5:"F5",F6:"F6",F7:"F7",F8:"F8",F9:"F9",F10:"F10",F11:"F11",F12:"F12"}}function s(e,t,n){const{listenOptions:{clickTarget:o}}=t,r=n;return r===document.body?null:o.some(e=>r.hasAttribute(e))?r:s(e,t,r.parentNode)}function c(e,t){const{ev:n,_findTarget:o,_readClickEvent:r,extra:i}=e,{listenOptions:s,currentContext:c}=t;let u=null,l=null,a=null,p=null,d=0;function f(){if(!u)return;const{left:e,top:o,width:s,height:f}=u.getBoundingClientRect(),h=window.scrollX,m=window.scrollY,g=r(l,d),v={target:u,x:l.clientX,y:l.clientY,context:c.name,note:c.note,options:t.listenOptions,event:l,dependencies:i,viewport:{X:h,Y:m,width:window.innerWidth,height:window.innerHeight},sizes:{width:s,height:f},position:{x:e,y:o},pagePosition:{x:e+h,y:o+m},type:"click"};n.emit(g,v),a=null,p=null,u=null,l=null,d=0}function h(n){let r=t.maxLeftClicks;if(clearTimeout(a),p)return clearTimeout(p),void(p=setTimeout(()=>p=null,s.mouseWait));if(u=o(e,t,n.target),null!=u){if(u&&u.dataset.hasOwnProperty("quickClick")&&(r=1),u&&"A"===u.tagName&&(r=1),l=n,d++,d>=r)return f(),void(r>1&&(p=setTimeout(()=>p=null,s.mouseWait)));a=setTimeout(f,s.mouseWait)}}function m(n){let r=t.maxRightClicks;if(clearTimeout(a),p)return clearTimeout(p),void(p=setTimeout(()=>p=null,s.mouseWait));if(u=o(e,t,n.target),null!=u){if(u&&u.dataset.hasOwnProperty("quickClick")&&(r=1),u&&"A"===u.tagName&&(r=1),l=n,d++,d>=r)return f(),void(r>1&&(p=setTimeout(()=>p=null,s.mouseWait)));a=setTimeout(f,s.mouseWait)}}return{start:function(){t.active||(window.addEventListener("contextmenu",m),document.addEventListener("click",h),t.active=!0)},stop:function(){t.active&&(window.removeEventListener("contextmenu",m),document.removeEventListener("click",h),t.active=!1,p&&(clearTimeout(p),p=null),u=null,l=null,d=0)}}}function u(e){const t=e.toUpperCase(),n=/CLICK\s*\:/i.test(t),o=["LEFT","MIDDLE","RIGHT"],r=["ALT","SHIFT","CTRL"];let i=null,s=0;const c=[],u=t.indexOf(":");return n?t.includes("SETUP")?"CLICK:SETUP":(t.slice(u+1).trim().split("-").map(e=>e.trim()).forEach(e=>{o.includes(e)?i=e:r.includes(e)?c.push(e):isNaN(e)||(s=e)}),`CLICK:${i}-${s}${c.length>0?"-":""}${c.sort().join("-")}`):e}function l(e,t){const{shiftKey:n,altKey:o,ctrlKey:r,key:i,button:s}=e,c=`CLICK:${["LEFT","MIDDLE","RIGHT"][s]}-${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 a(e,t){let n=0,o=!1;const r=t.defaultOptions,{regex:i}=e,{listenOptions:s,currentContext:{name:c},shortcuts:u}=t;return null==c||(Object.entries(u[c]).forEach(([c,u])=>{if(!i.test(c))return;if("CLICK:SETUP"===c){o=!0;const n=u.reduce((n,o)=>{const r=o({dependencies:e.extra,defaults:structuredClone(t.defaultOptions),options:s});return Object.assign(n,r)},r);return void Object.assign(t.listenOptions,n)}n++;const[l,a]=c.slice(6).split("-");"LEFT"===l&&t.maxLeftClicks<a&&(t.maxLeftClicks=a),"RIGHT"===l&&t.maxRightClicks<a&&(t.maxRightClicks=a)}),o||Object.assign(t.listenOptions,r)),n}function p(e,t){const{ev:n}=e;let o=null;function r(e,t,n,o){const{extra:r}=e,{left:i,top:s,width:c,height:u}=n.target.getBoundingClientRect(),l=window.scrollX,a=window.scrollY;return{target:n.target,context:t.currentContext.name,note:t.currentContext.note,event:n,dependencies:r,options:t.listenOptions,viewport:{X:l,Y:a,width:window.innerWidth,height:window.innerHeight},sizes:{width:c,height:u},position:{x:i,y:s},pagePosition:{x:i+l,y:s+a},type:o}}function i(o){const{callbacks:i,typeFn:s}=t;o.target;const c=r(e,t,o,"form"),u=`${s(c)}/in`;null!=i[u]&&n.emit(u,c,i[u])}function s(o){const{callbacks:i,typeFn:s}=t,c=r(e,t,o,"form"),u=`${s(c)}/out`;null!=i[u]&&n.emit(u,c,i[u])}function c(i){const{callbacks:s,typeFn:c}=t,u=r(e,t,i,"form"),l=c(u),a=t.wait[`${l}`],p=`${l}/instant`;null!=s[p]&&(0!==a?(clearTimeout(o),o=setTimeout(()=>n.emit(p,u,s[p]),a)):n.emit(p,u,s[p]))}return{start:function(){t.active||(document.addEventListener("focusin",i),document.addEventListener("focusout",s),document.addEventListener("input",c),t.active=!0)},stop:function(){t.active&&(document.removeEventListener("focusin",i),document.removeEventListener("focusout",s),document.removeEventListener("input",c),t.active=!1,o&&(clearTimeout(o),o=null))}}}function d(e){const t=e.toUpperCase(),n=/FORM\s*\:/i.test(t),o=t.indexOf(":");return n?`FORM:${t.slice(o+1).trim()}`:e}function f(e,t){const{regex:n,_defaults:o,ev:r}=e,{currentContext:{name:i,note:s},shortcuts:c,callbacks:u,ERROR_EVENT_NAME:l,defaultOptions:a}=t;let p=[],d=[],f=[],h=0;if(null==i)return!1;if(Object.entries(c[i]).forEach(([o,r])=>{if(n.test(o)){if(o.includes("SETUP")){const n=r.reduce((n,o)=>{const r=o({dependencies:e.extra,defaults:structuredClone(t.defaultOptions),options:t.listenOptions});return Object.assign(n,r)},a);return void Object.assign(t.listenOptions,n)}"FORM:WATCH"===o&&(p=r),"FORM:DEFINE"===o&&(d=r),"FORM:ACTION"===o&&(f=r)}}),0===f.length)return h;const m=new Set;0===d.length&&(d=[o.define]),0===p.length&&(p=[o.watch]);const g=p.map(n=>n({dependencies:e.extra,context:i,note:s,options:t.listenOptions})).reduce((e,t)=>(e.push(t),e),[]);return t.watchList=document.querySelectorAll(g),t.watchList.forEach(n=>{const{left:o,top:r,width:c,height:u}=n.getBoundingClientRect(),l=window.scrollX,a=window.scrollY;return m.add(d[0]({target:n,context:i,note:s,dependencies:e.extra,options:t.listenOptions,viewport:{X:l,Y:a,width:window.innerWidth,height:window.innerHeight},sizes:{width:c,height:u},position:{x:o,y:r},pagePosition:{x:o+l,y:r+a}}))}),t.typeFn=d[0]?d[0]:o.define,f.forEach(n=>{if(!(n instanceof Function))return r.emit(l,"The 'form:action' should be a function."),!1;const o=n({dependencies:e.extra,options:t.listenOptions});if(!(o instanceof Array))return r.emit(l,"Warning: The 'form:action' function should RETURN an array."),!1;o.forEach(({fn:e,type:n,timing:o,wait:i=0})=>{if(m.has(n)&&e instanceof Function){const t=`${n}/${o}`,i=u.hasOwnProperty(t);i?u[t].push(e):u[t]=[e],i||r.on(t,(e,t)=>{t.forEach(t=>{t instanceof Function&&t(e)})})}"instant"===o&&(t.wait[`${n}`]=i)})}),h=Object.keys(t.callbacks).length,h}const h={watch:()=>"input, select, textarea, button, a",define:({target:e})=>"checkbox"===e.type||"radio"===e.type?"checkbox":"button"==e.type||"submit"==e.type?"button":"input"};function m(e,t,n){const{listenOptions:{hoverTarget:o}}=t,r=n;return r!==document.body&&(r!==document&&(o.some(e=>r.hasAttribute(e))?r:m(e,t,r.parentNode)))}function g(e,t){const{ev:n,_findTarget:o,resetState:r,extra:i}=e;function s(r){const s=r.clientX,c=r.clientY,{hovered:u,hoverRectangle:l,listenOptions:a,hoverTimer:p,leaveTimer:d,lastEvent:f,lastHoverTarget:h}=t,m=o(e,t,r.target);if(!function(e,t,n){return!!e&&t>=e.left&&t<=e.right&&n>=e.top&&n<=e.bottom}(l,s,c)&&m!==u){if(u&&!m){if(t.hovered=!1,t.hoverRectangle=null,p&&(clearTimeout(p),t.hoverTimer=null),"off"===f)return;return void(t.leaveTimer=setTimeout(()=>{n.emit("HOVER:OFF",g(u)),t.leaveTimer=null,t.lastEvent="off"},a.wait))}u&&(n.emit("HOVER:OFF",g(u)),t.leaveTimer=null,t.lastEvent="off"),clearTimeout(d),clearTimeout(p),t.hovered=m,t.hoverRectangle=m.getBoundingClientRect(),t.hoverTimer=setTimeout(()=>{n.emit("HOVER:ON",g(m)),t.hoverTimer=null,t.lastHoverTarget=m,t.lastEvent="on"},a.wait)}function g(e){const{left:n,top:o,width:s,height:c}=e.getBoundingClientRect(),u=window.scrollX,l=window.scrollY;return{target:e,context:t.currentContext.name,note:t.currentContext.note,event:r,dependencies:i,options:t.listenOptions,viewport:{X:u,Y:l,width:window.innerWidth,height:window.innerHeight},sizes:{width:s,height:c},position:{x:n,y:o},pagePosition:{x:n+u,y:o+l},type:"hover"}}}return{start:function(){t.active||(document.addEventListener("mousemove",s),t.active=!0)},stop:function(){t.active&&(document.removeEventListener("mousemove",s),r())}}}function v(e){const t=e.toUpperCase(),n=/HOVER\s*\:/i.test(t),o=t.indexOf(":");return n?`HOVER:${t.slice(o+1).trim()}`:e}function y(e,t){let n=0,o=!1;const r=t.defaultOptions,{regex:i,_defaults:s,ev:c}=e,{currentContext:{name:u},shortcuts:l,ERROR_EVENT_NAME:a}=t;return null==u||(Object.entries(l[u]).forEach(([s,c])=>{if(i.test(s)){if("HOVER:SETUP"===s){o=!0;const n=c.reduce((n,o)=>{const r=o({dependencies:e.extra,defaults:structuredClone(t.defaultOptions),options:t.listenOptions});return Object.assign(n,r)},r);return void Object.assign(t.listenOptions,n)}n++}}),o||Object.assign(t.listenOptions,r)),n}function w(e,t){const{ev:n,resetState:o,extra:r}=e;let i=null,s=null;function c(e){e.clientX,e.clientY;const{lastPosition:o,lastDirection:c,listenOptions:u,currentContext:l}=t,{scrollWait:a,endScrollWait:p,minSpace:d}=u;if(!o)return;let f=null;const h=window.scrollX,m=window.scrollY,g=Math.abs(m-o.y),v=Math.abs(h-o.x);if(g<d&&v<d)return;const y=[];g>=d&&(m>o.y?y.push("down"):y.push("up")),v>=d&&(h>o.x?y.push("right"):y.push("left")),f=y[0]||null;const w=e=>({x:h,y:m,direction:e,context:l.name,note:l.note,dependencies:r,options:t.listenOptions,viewport:{X:h,Y:m,width:window.innerWidth,height:window.innerHeight},type:"scroll"});y.forEach(e=>{const t=`SCROLL:${e.toUpperCase()}`;n.emit(t,w(e))}),clearTimeout(i),clearTimeout(s);const x=y[y.length-1]||null;i=setTimeout(()=>{},a),s=setTimeout(()=>n.emit("SCROLL:END",w(x)),p),t.lastPosition={x:h,y:m},t.lastDirection=f}return{start:function(){t.active||(t.lastPosition={x:window.scrollX,y:window.scrollY},window.addEventListener("scroll",c),t.active=!0)},stop:function(){t.active&&(window.removeEventListener("scroll",c),o())}}}function x(e){const t=e.toUpperCase(),n=/SCROLL\s*\:/i.test(t),o=t.indexOf(":");return n?`SCROLL:${t.slice(o+1).trim()}`:e}function O(e,t){let n=0,o=!1;const r=t.defaultOptions,{regex:i}=e,{currentContext:{name:s},shortcuts:c}=t;return null==s||(Object.entries(c[s]).forEach(([s,c])=>{if(i.test(s)){if("SCROLL:SETUP"===s){o=!0;const n=c.reduce((n,o)=>{const r=o({dependencies:e.extra,defaults:structuredClone(t.defaultOptions),options:t.listenOptions});return Object.assign(n,r)},r);return void Object.assign(t.listenOptions,n)}n++}}),o||Object.assign(t.listenOptions,r)),n}function E(t={}){const n={},o={},r=function(){let e=Object.assign(Object.create(null),{"*":[]}),t=Object.create(null),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)),"*"!==n&&e[n]&&0===e[n].length&&delete e[n],void(t[n]&&0===t[n].length&&delete t[n]);t[n]&&delete t[n],"*"===n?e["*"]=[]:e[n]&&delete e[n]},reset:function(){e=Object.assign(Object.create(null),{"*":[]}),t=Object.create(null),n=new Set},emit:function(){const[i,...s]=arguments;function c(t){let o=!1;"*"!==t&&(n.has(t)||(e[t].every(e=>{const t=e(...s);return"string"!=typeof t||"STOP"!==t.toUpperCase()||(o=!0,!1)}),o||e["*"].forEach(e=>e(i,...s))))}if(o&&(console.log(`${r} Event "${String(i)}" was triggered.`),s.length>0&&(console.log("Arguments:"),console.log(...s),console.log("^----"))),"*"!==i){if(t[i]){if(n.has(i))return;const o=t[i];delete t[i],o.forEach(e=>e(...s)),e[i]||e["*"].forEach(e=>e(i,...s))}e[i]&&c(i)}else Reflect.ownKeys(e).forEach(e=>c(e))},stop:function(o){if("*"===o){const o=Reflect.ownKeys(e),r=Reflect.ownKeys(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)}}}(),i={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"},s={ev:r,inAPI:n,API:o,extra:{emit:r.emit}};return o.enablePlugin=(e,t={})=>{if("function"!=typeof e)return;const o=e(n._setupPlugin,t),r=o.getPrefix(),s=n._systemAction(r,"none");-1===s?(i.plugins.push(o),o.unmute()):(o.destroy(),i.plugins[s].unmute())},o.disablePlugin=e=>{const t=n._systemAction(e,"destroy");-1!==t&&i.plugins.splice(t,1)},o.mutePlugin=e=>n._systemAction(e,"mute"),o.unmutePlugin=e=>n._systemAction(e,"unmute"),o.listPlugins=()=>i.plugins.map(e=>e.getPrefix()),o.getContext=()=>i.currentContext.name,o.getNote=()=>i.currentContext.note,o.setNote=(e=null)=>{"string"!=typeof e&&null!=e||(i.currentContext.note=e)},o.pause=(e="*")=>{const t=n._readShortcutWithPlugins(e);r.stop(t)},o.resume=(e="*")=>{const t=n._readShortcutWithPlugins(e);r.start(t)},o.emit=(e,...t)=>r.emit(n._readShortcutWithPlugins(e),{dependencies:s.extra,type:"custom"},...t),o.listContexts=()=>Object.keys(i.shortcuts),o.setDependencies=e=>Object.assign(s.extra,e),o.getDependencies=()=>s.extra,o.reset=function(){r.reset(),o.changeContext(),i.plugins.forEach(e=>e.destroy()),o.listContexts().map(e=>o.unload(e)),s.extra={emit:r.emit},i.exposeShortcut=null},Object.entries(e).forEach(([e,t])=>{e.startsWith("_")?n[e]=t(s,i):o[e]=t(s,i)}),o}var S=Object.freeze({__proto__:null,pluginClick:function(e,t={}){const n={_findTarget:s,_readClickEvent:l,regex:/CLICK\s*\:/i},o={active:!1,maxLeftClicks:1,maxRightClicks:1,defaultOptions:{mouseWait:320,clickTarget:["data-click","href"]},listenOptions:{mouseWait:320,clickTarget:["data-click","href"]},streamKeys:!(!t.streamKeys||"function"!=typeof t.streamKeys)&&t.streamKeys};return n.resetState=function(){},e({prefix:"click",_normalizeShortcutName:u,_registerShortcutEvents:a,_listenDOM:c,pluginState:o,deps:n})},pluginForm:function(e,t={}){const n={_defaults:h,regex:/FORM\s*\:/i},o={callbacks:{},typeFn:"",watchList:[],wait:{},defaultOptions:{},listenOptions:{}};return n.resetState=function(){o.callbacks={},o.typeFn="",o.watchList=[],o.wait={}},e({prefix:"form",_normalizeShortcutName:d,_registerShortcutEvents:f,_listenDOM:p,pluginState:o,deps:n})},pluginHover:function(e,t={}){const n={_findTarget:m,regex:/HOVER\s*\:/i},o={active:!1,hovered:!1,hoverRectangle:null,hoverTimer:null,leaveTimer:null,lastEvent:"",lastHoverTarget:null,defaultOptions:{hoverTarget:["data-hover"],wait:320},listenOptions:{hoverTarget:["data-hover"],wait:320}};return n.resetState=function(){o.active=!1,o.hovered=!1,o.hoverRectangle=null,clearTimeout(o.hoverTimer),clearTimeout(o.leaveTimer),o.hoverTimer=null,o.leaveTimer=null,o.lastHoverTarget=null},e({prefix:"hover",_normalizeShortcutName:v,_registerShortcutEvents:y,_listenDOM:g,pluginState:o,deps:n})},pluginKey:function(e,s={}){const c={_specialChars:i,_readKeyEvent:o,regex:/KEY\s*\:/i},u={active:!1,maxSequence:1,keyIgnore:null,defaultOptions:{keyWait:480},listenOptions:{keyWait:480},streamKeys:!(!s.streamKeys||"function"!=typeof s.streamKeys)&&s.streamKeys};return c.resetState=function(){u.active=!1,u.keyIgnore=null,u.maxSequence=1},e({prefix:"key",_normalizeShortcutName:n,_registerShortcutEvents:r,_listenDOM:t,pluginState:u,deps:c})},pluginScroll:function(e,t={}){const n={regex:/SCROLL\s*\:/i},o={active:!1,lastPosition:null,lastDirection:null,defaultOptions:{scrollWait:50,endScrollWait:400,minSpace:40},listenOptions:{scrollWait:50,endScrollWait:400,minSpace:40}};return n.resetState=function(){o.active=!1},e({prefix:"scroll",_normalizeShortcutName:x,_registerShortcutEvents:O,_listenDOM:w,pluginState:o,deps:n})},shortcuts:E});function T(e){return e?function(e){let t=e.map(e=>C()),n=t.map(e=>e.promise);t.promises=t;let o=k(Promise.all(n));function r(e){let t="pending";return e.then(()=>t="fulfilled").catch(()=>t="rejected"),t}function i(n,...o){t.forEach((t,i)=>n({value:e[i],done:t.done,cancel:t.cancel,timeout:t.timeout,state:r(t.promise)},...o))}const s={promise:Promise.all(n),promises:t,done:e=>{t.forEach(t=>t.done(e))},cancel:e=>{t.forEach(t=>t.cancel(e))},each:i,onComplete:o,timeout:()=>{}};return s.timeout=P(!0,s),s}(e):C()}function C(){let e,t;const n=new Promise((n,o)=>{e=n,t=o}),o={promise:n,promises:null,done:e,cancel:t,each:()=>{},onComplete:k(n),timeout:()=>{}};return o.timeout=P(!1,o),o.each=(n,...r)=>{n({value:null,done:e,cancel:t,timeout:o.timeout},...r)},o}function k(e){return function(t,n=null){null===n?e.then(e=>t(e)):e.then(e=>t(e),e=>n(e))}}function P(e,t){let n;return n=e?Promise.all(t.promises.map(e=>e.promise)):t.promise,function(e,o){let r,i=new Promise((t,i)=>{r=setTimeout(()=>{t(o),Promise.resolve(n)},e)});return n.then(()=>clearTimeout(r)),t.onComplete=k(Promise.race([n,i])),t}}function b({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 R(e={},t=b){return function({message:n,type:o,level:r,...i}){const{level:s,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:s,...i})}}function*L(e,t,n,o){let r=null,i=!0;if(null===e)return yield*o.map(e=>[e,"show"]),void(yield[n,"show"]);if(0!==o.length){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"]}else{if(yield[e,"hide"],t.includes(n)){let e=t.indexOf(n),o=t.filter((t,n)=>n>e);o.reverse(),yield*o.map(e=>[e,"hide"]),i=!1}else{let e=[...t];e.reverse(),yield*e.map(e=>[e,"hide"])}i&&(yield[n,"show"])}}function _(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 T.sequence=function(e,...t){const n=T(),o=[];const r=function*(e){for(const t of e)yield t}(e);return function e(t,...i){t.done?n.done(o):t.value(...i).then(t=>{o.push(t),e(r.next(),...i,t)})}(r.next(),...t),n},T.all=function(e,...t){const n=T(),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={}){const t=E({errorEventName:"@app-error"}),n=R({level:e.logLevel??1},e=>{const{type:n,logLevel:o}=e;0!==o&&"error"===n&&t.getDependencies().emit("@app-error",e)}),o={currentScene:null,currentParents:null,sceneNames:new Set,scenes:{},opened:!1,jumpStack:[]},r={},i={shortcutMngr:t,findInstructions:L,askForPromise:T,setInstruction:_({askForPromise:T,deps:t.getDependencies}),log:n};return r.hide=function(e,t){return function(n=1){const{askForPromise:o,shortcutMngr:r,setInstruction:i}=e,{currentScene:s,currentParents:c,scenes:u}=t,l=o(),a=[],p=c.length>0;r.pause(),a.push(i(u[s].hide)),p||(t.currentScene=null);let d=[];return p&&"*"===n&&(d=[...c].reverse()),p&&!["*",1].includes(n)&&(d=c.slice("-"+(n-1)).reverse()),p&&0===d.length&&"*"===u[s].parents[0]&&(t.currentScene=t.currentParents.pop(),t.currentParents=t.currentScene?[...u[t.currentScene].parents]:[]),d.forEach(e=>{a.push(i(u[e].hide)),t.currentScene="*"===u[e].parents[0]?null:u[e].parents.at(-1)??null,t.currentParents=t.currentScene?u[t.currentScene].parents:[]}),o.sequence(a).onComplete(()=>{r.changeContext(t.currentScene),l.done()}),l.promise}}(i,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:i,parents:s,beforeHide:c,afterShow:u,...l}=n[e];return Object.keys(l)}}(0,o),r.setScenes=function(e,t){return function(n){const{shortcutMngr:o,log:r}=e;n.forEach(e=>{if(null==e)return;const{name:n,scene:i}=e;if(!n)return void r({message:"Scene name is not defined",level:1,type:"error"});if(null==i)return void r({message:`Scene ${n} is not defined`,level:1,type:"error"});i.parents||(i.parents=[]),t.scenes[n]=i,t.sceneNames.add(n);const{show:s,hide:c,parents:u,...l}=i,a={};a[n]=l,o.load(a)})}}(i,o),r.show=function(e,t){return function({scene:n,options:o={ssr:!1}},...r){const{shortcutMngr:i,askForPromise:s,log:c,findInstructions:u,setInstruction:l}=e,a=s(),p=s(),{opened:d,scenes:f,sceneNames:h,currentScene:m}=t;return m&&"function"==typeof f[m].beforeHide?(0,f[m].beforeHide)({done:p.done,dependencies:i.getDependencies()}):p.done(!0),p.onComplete(e=>{if(!e)return a.done(),a.promise;if(!h.has(n))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.currentScene=n,i.changeContext(n),a.done(),a.promise;const{show:p,parents:m=[]}=f[n];if(t.currentParents||(t.currentParents=[]),"*"===m[0])return l(p,...r)().then(()=>a.done()),t.currentParents.push(t.currentScene),t.currentScene=n,i.changeContext(n),a.promise;if(0!==m.length&&!m.every(e=>h.has(e)))return c({message:`Some of '${n}' parent scenes are not set.`,level:1,type:"error"}),a.done(),a.promise;function g([e,n]){if("show"===n)t.currentScene&&(t.currentParents=[...f[t.currentScene].parents]),t.currentScene=e;else{let n="*"===f[e].parents[0]?t.currentParents.pop():f[e].parents.at(-1);t.currentScene=n}return f[e][n]}const v=u(t.currentScene,t.currentParents,n,m),y=[];for(let e of v){const t=g(e);y.push(l(t,...r))}s.sequence(y).onComplete(()=>{t.opened=!0,t.currentScene=n,t.currentParents=f[n].parents?[...f[n].parents]:null,i.changeContext(n),"function"==typeof f[n].afterShow&&f[n].afterShow({dependencies:i.getDependencies(),done:()=>{}}),a.done()})}),a.promise}}(i,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 S});return t.map(e=>n[e])},r.setDependencies=e=>t.setDependencies(e),r.getDependencies=()=>t.getDependencies(),r.setNote=e=>t.setNote(e),r.listScenes=()=>[...o.sceneNames],r.enablePlugin=(e,n)=>t.enablePlugin(e,n),r.disablePlugin=e=>t.disablePlugin(e),r.getState=()=>({scene:o.currentScene,parents:o.currentParents?[...o.currentParents]:o.currentParents,opened:o.opened}),r.emit=(e,...n)=>t.getDependencies().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,i])=>{const r=e(o);r!==o&&(delete n[t][o],n[t][r]=i)})})}},_readShortcutWithPlugins:function(e,t){return function(n){const{inAPI:o}=e,i=n.split(":")[0].toLowerCase().trim(),r=o._systemAction(i,"none");let s=n;return-1!==r&&(s=t.plugins[r].shortcutName(n)),s}},_setupPlugin:function(e,t){const{inAPI:n}=e,{currentContext:o,shortcuts:i,exposeShortcut:r,ERROR_EVENT_NAME:s}=t;return function(t){const{prefix:c,_normalizeShortcutName:u,_registerShortcutEvents:l,_listenDOM:a,pluginState:d,deps:p}=t,{resetState:f}=p;d.currentContext=o,d.shortcuts=i,d.exposeShortcut=r,d.ERROR_EVENT_NAME=s;const h={ev:e.ev,extra:e.extra,...p};n._normalizeWithPlugins(u);let m=l(h,d);const g=a(h,d);m>0&&g.start();const v={getPrefix:()=>c,shortcutName:e=>u(e),contextChange:()=>{f(),m=l(h,d),m<1&&g.stop(),m>0&&g.start()},mute:()=>g.stop(),unmute:()=>g.start(),destroy:()=>{g.stop(),f()}};return Object.freeze(v),v}},_systemAction:function(e,t){return function(e,n,o=null){return t.plugins.findIndex(t=>t.getPrefix()===e&&(t[n]&&t[n](o),!0))}},changeContext:function(e,t){const{shortcuts:n,currentContext:o,ERROR_EVENT_NAME:i}=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])=>{e.includes(":SETUP")||t.forEach(t=>r.on(e,t))}),r.on("*",(...e)=>{t.exposeShortcut&&t.exposeShortcut(...e)})):r.emit(i,`Context '${e}' does not exist`))}},listShortcuts:function(e,t){const n=t.shortcuts;return function(e=null){if(null!=e){const t=n[e];return null==t?null:Object.entries(t).map(([e,t])=>e)}return Object.keys(n).map(e=>{const 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:i,getContext:r}}=e;return function(e){const t=r(),s=o.map(e=>e.getPrefix().toUpperCase());let c=!1;Object.entries(e).forEach(([e,i])=>{e===t&&(c=!0),n[e]={},Object.entries(i).forEach(([t,i])=>{let r=t;const c=t.toUpperCase().trim(),u=s.map((e,t)=>c.startsWith(e)?t:null).filter(e=>null!==e);if(u.length){const e=u[0];r=o[e].shortcutName(t)}i instanceof Function&&(i=[i]),n[e][r]=i})}),c&&(i(),i(t))}},unload:function(e,t){const{currentContext:n,shortcuts:o,ERROR_EVENT_NAME:i}=t,{ev:r}=e;return function(e){n.name!==e?o[e]?delete o[e]:r.emit(i,`Context '${e}' does not exist`):r.emit(i,`Context '${e}' can't be removed during is current active context. Change the context first`)}}};function t(e,t){const{ev:n,_specialChars:o,_readKeyEvent:i,extra:r,resetState:s}=e,{currentContext:c,streamKeys:u,listenOptions:l}=t;let a=[],d=null,p=!0,f=!1;const h=()=>p=!1,m=()=>p=!0,g=()=>f=!0,v=()=>!1===p;function y(){const e=a.map(e=>[e.join("+")]),o={wait:h,end:m,ignore:g,isWaiting:v,note:c.note,context:c.name,dependencies:r,options:t.listenOptions,viewport:{X:window.scrollX,Y:window.scrollY,width:window.innerWidth,height:window.innerHeight},type:"key"};if(!p){const t=`KEY:${e.at(-1).join("+")}`;n.emit(t,o),f&&(a=a.slice(0,-1),f=!1)}if(p){const i=`KEY:${e.join(",")}`;n.emit(i,o),f&&(a=a.slice(0,-1),f=!1),a=[],clearTimeout(t.keyIgnore),t.keyIgnore=null,clearTimeout(d),d=null}}function w(n){if(clearTimeout(d),o().hasOwnProperty(n.code))return a.push(i(n,o)),u&&u({key:n.key,context:c.name,note:c.note,dependencies:e.extra}),t.keyIgnore?(clearTimeout(t.keyIgnore),t.keyIgnore=setTimeout(()=>t.keyIgnore=null,l.keyWait),void a.pop()):p&&a.length===t.maxSequence?(y(),void(t.keyIgnore=setTimeout(()=>t.keyIgnore=null,l.keyWait))):void(p?d=setTimeout(y,l.keyWait):y())}function x(n){if(!o().hasOwnProperty(n.code)){if(clearTimeout(d),u&&u({key:n.key,context:c.name,note:c.note,dependencies:e.extra}),t.keyIgnore)return clearTimeout(t.keyIgnore),void(t.keyIgnore=setTimeout(()=>t.keyIgnore=null,l.keyWait));if(a.push(i(n,o)),p&&a.length===t.maxSequence)return y(),void(t.keyIgnore=setTimeout(()=>t.keyIgnore=null,l.keyWait));p?d=setTimeout(y,l.keyWait):y()}}return{start:function(){t.active||(document.addEventListener("keydown",w),document.addEventListener("keypress",x),t.active=!0)},stop:function(){t.active&&(document.removeEventListener("keydown",w),document.removeEventListener("keypress",x),t.active=!1,d&&(clearTimeout(d),d=null),t.keyIgnore&&(clearTimeout(t.keyIgnore),t.keyIgnore=null),a=[],p=!0,f=!1)}}}function n(e){const t=e.toUpperCase(),n=/KEY\s*\:/i.test(t),o=t.indexOf(":");return n?t.includes("SETUP")?"KEY:SETUP":`KEY:${t.slice(o+1).split(",").map(e=>e.trim()).map(e=>e.split("+").map(e=>e.trim()).sort().join("+")).join(",")}`:e}function o(e,t){const{shiftKey:n,altKey:o,ctrlKey:i}=e,r=t(),s=e.code.replace("Key","").replace("Digit",""),c=[];return i&&c.push("CTRL"),n&&c.push("SHIFT"),o&&c.push("ALT"),r.hasOwnProperty(s)?c.push(r[s].toUpperCase()):["ControlLeft","ControlRight","ShiftLeft","ShiftRight","AltLeft","AltRight","Meta"].includes(s)||c.push(s.toUpperCase()),c.sort()}function i(e,t){let n=0,o=!1;const i=t.defaultOptions,{regex:r}=e,{currentContext:{name:s},shortcuts:c}=t;return null==s?0:(Object.entries(c[s]).forEach(([s,c])=>{if(!r.test(s))return;if("KEY:SETUP"===s){o=!0;const n=c.reduce((n,o)=>{const i=o({dependencies:e.extra,defaults:structuredClone(t.defaultOptions),options:t.listenOptions});return Object.assign(n,i)},i);return void Object.assign(t.listenOptions,n)}n++;const u=s.slice(4).split(",").length;t.maxSequence<u&&(t.maxSequence=u)}),o||Object.assign(t.listenOptions,i),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,i=n;return i===document.body?null:o.some(e=>i.hasAttribute(e))?i:s(e,t,i.parentNode)}function c(e,t){const{ev:n,_findTarget:o,_readClickEvent:i,extra:r}=e,{listenOptions:s,currentContext:c}=t;let u=null,l=null,a=null,d=null,p=0;function f(){if(!u)return;const{left:e,top:o,width:s,height:f}=u.getBoundingClientRect(),h=window.scrollX,m=window.scrollY,g=i(l,p),v={target:u,x:l.clientX,y:l.clientY,context:c.name,note:c.note,options:t.listenOptions,event:l,dependencies:r,viewport:{X:h,Y:m,width:window.innerWidth,height:window.innerHeight},sizes:{width:s,height:f},position:{x:e,y:o},pagePosition:{x:e+h,y:o+m},type:"click"};n.emit(g,v),a=null,d=null,u=null,l=null,p=0}function h(n){let i=t.maxLeftClicks;if(clearTimeout(a),d)return clearTimeout(d),void(d=setTimeout(()=>d=null,s.mouseWait));if(u=o(e,t,n.target),null!=u){if(u&&u.dataset.hasOwnProperty("quickClick")&&(i=1),u&&"A"===u.tagName&&(i=1),l=n,p++,p>=i)return f(),void(i>1&&(d=setTimeout(()=>d=null,s.mouseWait)));a=setTimeout(f,s.mouseWait)}}function m(n){let i=t.maxRightClicks;if(clearTimeout(a),d)return clearTimeout(d),void(d=setTimeout(()=>d=null,s.mouseWait));if(u=o(e,t,n.target),null!=u){if(u&&u.dataset.hasOwnProperty("quickClick")&&(i=1),u&&"A"===u.tagName&&(i=1),l=n,p++,p>=i)return f(),void(i>1&&(d=setTimeout(()=>d=null,s.mouseWait)));a=setTimeout(f,s.mouseWait)}}return{start:function(){t.active||(window.addEventListener("contextmenu",m),document.addEventListener("click",h),t.active=!0)},stop:function(){t.active&&(window.removeEventListener("contextmenu",m),document.removeEventListener("click",h),t.active=!1,d&&(clearTimeout(d),d=null),u=null,l=null,p=0)}}}function u(e){const t=e.toUpperCase(),n=/CLICK\s*\:/i.test(t),o=["LEFT","MIDDLE","RIGHT"],i=["ALT","SHIFT","CTRL"];let r=null,s=0;const c=[],u=t.indexOf(":");return n?t.includes("SETUP")?"CLICK:SETUP":(t.slice(u+1).trim().split("-").map(e=>e.trim()).forEach(e=>{o.includes(e)?r=e:i.includes(e)?c.push(e):isNaN(e)||(s=e)}),`CLICK:${r}-${s}${c.length>0?"-":""}${c.sort().join("-")}`):e}function l(e,t){const{shiftKey:n,altKey:o,ctrlKey:i,key:r,button:s}=e,c=`CLICK:${["LEFT","MIDDLE","RIGHT"][s]}-${t}`,u=[];return i&&u.push("CTRL"),n&&u.push("SHIFT"),o&&u.push("ALT"),u.length>0?`${c}${u.length>0?"-":""}${u.sort().join("-")}`:`${c}`}function a(e,t){let n=0,o=!1;const i=t.defaultOptions,{regex:r}=e,{listenOptions:s,currentContext:{name:c},shortcuts:u}=t;return null==c||(Object.entries(u[c]).forEach(([c,u])=>{if(!r.test(c))return;if("CLICK:SETUP"===c){o=!0;const n=u.reduce((n,o)=>{const i=o({dependencies:e.extra,defaults:structuredClone(t.defaultOptions),options:s});return Object.assign(n,i)},i);return void Object.assign(t.listenOptions,n)}n++;const[l,a]=c.slice(6).split("-");"LEFT"===l&&t.maxLeftClicks<a&&(t.maxLeftClicks=a),"RIGHT"===l&&t.maxRightClicks<a&&(t.maxRightClicks=a)}),o||Object.assign(t.listenOptions,i)),n}function d(e,t){const{ev:n}=e;let o=null;function i(e,t,n,o){const{extra:i}=e,{left:r,top:s,width:c,height:u}=n.target.getBoundingClientRect(),l=window.scrollX,a=window.scrollY;return{target:n.target,context:t.currentContext.name,note:t.currentContext.note,event:n,dependencies:i,options:t.listenOptions,viewport:{X:l,Y:a,width:window.innerWidth,height:window.innerHeight},sizes:{width:c,height:u},position:{x:r,y:s},pagePosition:{x:r+l,y:s+a},type:o}}function r(o){const{callbacks:r,typeFn:s}=t;o.target;const c=i(e,t,o,"form"),u=`${s(c)}/in`;null!=r[u]&&n.emit(u,c,r[u])}function s(o){const{callbacks:r,typeFn:s}=t,c=i(e,t,o,"form"),u=`${s(c)}/out`;null!=r[u]&&n.emit(u,c,r[u])}function c(r){const{callbacks:s,typeFn:c}=t,u=i(e,t,r,"form"),l=c(u),a=t.wait[`${l}`],d=`${l}/instant`;null!=s[d]&&(0!==a?(clearTimeout(o),o=setTimeout(()=>n.emit(d,u,s[d]),a)):n.emit(d,u,s[d]))}return{start:function(){t.active||(document.addEventListener("focusin",r),document.addEventListener("focusout",s),document.addEventListener("input",c),t.active=!0)},stop:function(){t.active&&(document.removeEventListener("focusin",r),document.removeEventListener("focusout",s),document.removeEventListener("input",c),t.active=!1,o&&(clearTimeout(o),o=null))}}}function p(e){const t=e.toUpperCase(),n=/FORM\s*\:/i.test(t),o=t.indexOf(":");return n?`FORM:${t.slice(o+1).trim()}`:e}function f(e,t){const{regex:n,_defaults:o,ev:i}=e,{currentContext:{name:r,note:s},shortcuts:c,callbacks:u,ERROR_EVENT_NAME:l,defaultOptions:a}=t;let d=[],p=[],f=[],h=0;if(null==r)return!1;if(Object.entries(c[r]).forEach(([o,i])=>{if(n.test(o)){if(o.includes("SETUP")){const n=i.reduce((n,o)=>{const i=o({dependencies:e.extra,defaults:structuredClone(t.defaultOptions),options:t.listenOptions});return Object.assign(n,i)},a);return void Object.assign(t.listenOptions,n)}"FORM:WATCH"===o&&(d=i),"FORM:DEFINE"===o&&(p=i),"FORM:ACTION"===o&&(f=i)}}),0===f.length)return h;const m=new Set;0===p.length&&(p=[o.define]),0===d.length&&(d=[o.watch]);const g=d.map(n=>n({dependencies:e.extra,context:r,note:s,options:t.listenOptions})).reduce((e,t)=>(e.push(t),e),[]);return t.watchList=document.querySelectorAll(g),t.watchList.forEach(n=>{const{left:o,top:i,width:c,height:u}=n.getBoundingClientRect(),l=window.scrollX,a=window.scrollY;return m.add(p[0]({target:n,context:r,note:s,dependencies:e.extra,options:t.listenOptions,viewport:{X:l,Y:a,width:window.innerWidth,height:window.innerHeight},sizes:{width:c,height:u},position:{x:o,y:i},pagePosition:{x:o+l,y:i+a}}))}),t.typeFn=p[0]?p[0]:o.define,f.forEach(n=>{if(!(n instanceof Function))return i.emit(l,"The 'form:action' should be a function."),!1;const o=n({dependencies:e.extra,options:t.listenOptions});if(!(o instanceof Array))return i.emit(l,"Warning: The 'form:action' function should RETURN an array."),!1;o.forEach(({fn:e,type:n,timing:o,wait:r=0})=>{if(m.has(n)&&e instanceof Function){const t=`${n}/${o}`,r=u.hasOwnProperty(t);r?u[t].push(e):u[t]=[e],r||i.on(t,(e,t)=>{t.forEach(t=>{t instanceof Function&&t(e)})})}"instant"===o&&(t.wait[`${n}`]=r)})}),h=Object.keys(t.callbacks).length,h}const h={watch:()=>"input, select, textarea, button, a",define:({target:e})=>"checkbox"===e.type||"radio"===e.type?"checkbox":"button"==e.type||"submit"==e.type?"button":"input"};function m(e,t,n){const{listenOptions:{hoverTarget:o}}=t,i=n;return i!==document.body&&(i!==document&&(o.some(e=>i.hasAttribute(e))?i:m(e,t,i.parentNode)))}function g(e,t){const{ev:n,_findTarget:o,resetState:i,extra:r}=e;function s(i){const s=i.clientX,c=i.clientY,{hovered:u,hoverRectangle:l,listenOptions:a,hoverTimer:d,leaveTimer:p,lastEvent:f,lastHoverTarget:h}=t,m=o(e,t,i.target);if(!function(e,t,n){return!!e&&t>=e.left&&t<=e.right&&n>=e.top&&n<=e.bottom}(l,s,c)&&m!==u){if(u&&!m){if(t.hovered=!1,t.hoverRectangle=null,d&&(clearTimeout(d),t.hoverTimer=null),"off"===f)return;return void(t.leaveTimer=setTimeout(()=>{n.emit("HOVER:OFF",g(u)),t.leaveTimer=null,t.lastEvent="off"},a.wait))}u&&(n.emit("HOVER:OFF",g(u)),t.leaveTimer=null,t.lastEvent="off"),clearTimeout(p),clearTimeout(d),t.hovered=m,t.hoverRectangle=m.getBoundingClientRect(),t.hoverTimer=setTimeout(()=>{n.emit("HOVER:ON",g(m)),t.hoverTimer=null,t.lastHoverTarget=m,t.lastEvent="on"},a.wait)}function g(e){const{left:n,top:o,width:s,height:c}=e.getBoundingClientRect(),u=window.scrollX,l=window.scrollY;return{target:e,context:t.currentContext.name,note:t.currentContext.note,event:i,dependencies:r,options:t.listenOptions,viewport:{X:u,Y:l,width:window.innerWidth,height:window.innerHeight},sizes:{width:s,height:c},position:{x:n,y:o},pagePosition:{x:n+u,y:o+l},type:"hover"}}}return{start:function(){t.active||(document.addEventListener("mousemove",s),t.active=!0)},stop:function(){t.active&&(document.removeEventListener("mousemove",s),i())}}}function v(e){const t=e.toUpperCase(),n=/HOVER\s*\:/i.test(t),o=t.indexOf(":");return n?`HOVER:${t.slice(o+1).trim()}`:e}function y(e,t){let n=0,o=!1;const i=t.defaultOptions,{regex:r,_defaults:s,ev:c}=e,{currentContext:{name:u},shortcuts:l,ERROR_EVENT_NAME:a}=t;return null==u||(Object.entries(l[u]).forEach(([s,c])=>{if(r.test(s)){if("HOVER:SETUP"===s){o=!0;const n=c.reduce((n,o)=>{const i=o({dependencies:e.extra,defaults:structuredClone(t.defaultOptions),options:t.listenOptions});return Object.assign(n,i)},i);return void Object.assign(t.listenOptions,n)}n++}}),o||Object.assign(t.listenOptions,i)),n}function w(e,t){const{ev:n,resetState:o,extra:i}=e;let r=null,s=null;function c(e){e.clientX,e.clientY;const{lastPosition:o,lastDirection:c,listenOptions:u,currentContext:l}=t,{scrollWait:a,endScrollWait:d,minSpace:p}=u;if(!o)return;let f=null;const h=window.scrollX,m=window.scrollY,g=Math.abs(m-o.y),v=Math.abs(h-o.x);if(g<p&&v<p)return;const y=[];g>=p&&(m>o.y?y.push("down"):y.push("up")),v>=p&&(h>o.x?y.push("right"):y.push("left")),f=y[0]||null;const w=e=>({x:h,y:m,direction:e,context:l.name,note:l.note,dependencies:i,options:t.listenOptions,viewport:{X:h,Y:m,width:window.innerWidth,height:window.innerHeight},type:"scroll"});y.forEach(e=>{const t=`SCROLL:${e.toUpperCase()}`;n.emit(t,w(e))}),clearTimeout(r),clearTimeout(s);const x=y[y.length-1]||null;r=setTimeout(()=>{},a),s=setTimeout(()=>n.emit("SCROLL:END",w(x)),d),t.lastPosition={x:h,y:m},t.lastDirection=f}return{start:function(){t.active||(t.lastPosition={x:window.scrollX,y:window.scrollY},window.addEventListener("scroll",c),t.active=!0)},stop:function(){t.active&&(window.removeEventListener("scroll",c),o())}}}function x(e){const t=e.toUpperCase(),n=/SCROLL\s*\:/i.test(t),o=t.indexOf(":");return n?`SCROLL:${t.slice(o+1).trim()}`:e}function O(e,t){let n=0,o=!1;const i=t.defaultOptions,{regex:r}=e,{currentContext:{name:s},shortcuts:c}=t;return null==s||(Object.entries(c[s]).forEach(([s,c])=>{if(r.test(s)){if("SCROLL:SETUP"===s){o=!0;const n=c.reduce((n,o)=>{const i=o({dependencies:e.extra,defaults:structuredClone(t.defaultOptions),options:t.listenOptions});return Object.assign(n,i)},i);return void Object.assign(t.listenOptions,n)}n++}}),o||Object.assign(t.listenOptions,i)),n}function E(t={}){const n={},o={},i=function(){let e=Object.assign(Object.create(null),{"*":[]}),t=Object.create(null),n=new Set,o=!1,i="";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)),"*"!==n&&e[n]&&0===e[n].length&&delete e[n],void(t[n]&&0===t[n].length&&delete t[n]);t[n]&&delete t[n],"*"===n?e["*"]=[]:e[n]&&delete e[n]},reset:function(){e=Object.assign(Object.create(null),{"*":[]}),t=Object.create(null),n=new Set},emit:function(){const[r,...s]=arguments;function c(t){let o=!1;"*"!==t&&(n.has(t)||(e[t].every(e=>{const t=e(...s);return"string"!=typeof t||"STOP"!==t.toUpperCase()||(o=!0,!1)}),o||e["*"].forEach(e=>e(r,...s))))}if(o&&(console.log(`${i} Event "${String(r)}" was triggered.`),s.length>0&&(console.log("Arguments:"),console.log(...s),console.log("^----"))),"*"!==r){if(t[r]){if(n.has(r))return;const o=t[r];delete t[r],o.forEach(e=>e(...s)),e[r]||e["*"].forEach(e=>e(r,...s))}e[r]&&c(r)}else Reflect.ownKeys(e).forEach(e=>c(e))},stop:function(o){if("*"===o){const o=Reflect.ownKeys(e),i=Reflect.ownKeys(t);return void(n=new Set([...i,...o]))}n.add(o)},start:function(e){"*"!==e?n.delete(e):n.clear()},debug:function(e,t){o=!!e,t&&"string"==typeof t&&(i=t)}}}(),r={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"},s={ev:i,inAPI:n,API:o,extra:{emit:i.emit}};return o.enablePlugin=(e,t={})=>{if("function"!=typeof e)return;const o=e(n._setupPlugin,t),i=o.getPrefix(),s=n._systemAction(i,"none");-1===s?(r.plugins.push(o),o.unmute()):(o.destroy(),r.plugins[s].unmute())},o.disablePlugin=e=>{const t=n._systemAction(e,"destroy");-1!==t&&r.plugins.splice(t,1)},o.mutePlugin=e=>n._systemAction(e,"mute"),o.unmutePlugin=e=>n._systemAction(e,"unmute"),o.listPlugins=()=>r.plugins.map(e=>e.getPrefix()),o.getContext=()=>r.currentContext.name,o.getNote=()=>r.currentContext.note,o.setNote=(e=null)=>{"string"!=typeof e&&null!=e||(r.currentContext.note=e)},o.pause=(e="*")=>{const t=n._readShortcutWithPlugins(e);i.stop(t)},o.resume=(e="*")=>{const t=n._readShortcutWithPlugins(e);i.start(t)},o.emit=(e,...t)=>i.emit(n._readShortcutWithPlugins(e),{dependencies:s.extra,type:"custom"},...t),o.listContexts=()=>Object.keys(r.shortcuts),o.setDependencies=e=>Object.assign(s.extra,e),o.getDependencies=()=>s.extra,o.reset=function(){i.reset(),o.changeContext(),r.plugins.forEach(e=>e.destroy()),o.listContexts().map(e=>o.unload(e)),s.extra={emit:i.emit},r.exposeShortcut=null},Object.entries(e).forEach(([e,t])=>{e.startsWith("_")?n[e]=t(s,r):o[e]=t(s,r)}),o}var S=Object.freeze({__proto__:null,pluginClick:function(e,t={}){const n={_findTarget:s,_readClickEvent:l,regex:/CLICK\s*\:/i},o={active:!1,maxLeftClicks:1,maxRightClicks:1,defaultOptions:{mouseWait:320,clickTarget:["data-click","href"]},listenOptions:{mouseWait:320,clickTarget:["data-click","href"]},streamKeys:!(!t.streamKeys||"function"!=typeof t.streamKeys)&&t.streamKeys};return n.resetState=function(){},e({prefix:"click",_normalizeShortcutName:u,_registerShortcutEvents:a,_listenDOM:c,pluginState:o,deps:n})},pluginForm:function(e,t={}){const n={_defaults:h,regex:/FORM\s*\:/i},o={callbacks:{},typeFn:"",watchList:[],wait:{},defaultOptions:{},listenOptions:{}};return n.resetState=function(){o.callbacks={},o.typeFn="",o.watchList=[],o.wait={}},e({prefix:"form",_normalizeShortcutName:p,_registerShortcutEvents:f,_listenDOM:d,pluginState:o,deps:n})},pluginHover:function(e,t={}){const n={_findTarget:m,regex:/HOVER\s*\:/i},o={active:!1,hovered:!1,hoverRectangle:null,hoverTimer:null,leaveTimer:null,lastEvent:"",lastHoverTarget:null,defaultOptions:{hoverTarget:["data-hover"],wait:320},listenOptions:{hoverTarget:["data-hover"],wait:320}};return n.resetState=function(){o.active=!1,o.hovered=!1,o.hoverRectangle=null,clearTimeout(o.hoverTimer),clearTimeout(o.leaveTimer),o.hoverTimer=null,o.leaveTimer=null,o.lastHoverTarget=null},e({prefix:"hover",_normalizeShortcutName:v,_registerShortcutEvents:y,_listenDOM:g,pluginState:o,deps:n})},pluginKey:function(e,s={}){const c={_specialChars:r,_readKeyEvent:o,regex:/KEY\s*\:/i},u={active:!1,maxSequence:1,keyIgnore:null,defaultOptions:{keyWait:480},listenOptions:{keyWait:480},streamKeys:!(!s.streamKeys||"function"!=typeof s.streamKeys)&&s.streamKeys};return c.resetState=function(){u.active=!1,u.keyIgnore=null,u.maxSequence=1},e({prefix:"key",_normalizeShortcutName:n,_registerShortcutEvents:i,_listenDOM:t,pluginState:u,deps:c})},pluginScroll:function(e,t={}){const n={regex:/SCROLL\s*\:/i},o={active:!1,lastPosition:null,lastDirection:null,defaultOptions:{scrollWait:50,endScrollWait:400,minSpace:40},listenOptions:{scrollWait:50,endScrollWait:400,minSpace:40}};return n.resetState=function(){o.active=!1},e({prefix:"scroll",_normalizeShortcutName:x,_registerShortcutEvents:O,_listenDOM:w,pluginState:o,deps:n})},shortcuts:E});function T(e){return e?function(e){let t=e.map(e=>C()),n=t.map(e=>e.promise);t.promises=t;let o=k(Promise.all(n));function i(e){let t="pending";return e.then(()=>t="fulfilled").catch(()=>t="rejected"),t}function r(n,...o){t.forEach((t,r)=>n({value:e[r],done:t.done,cancel:t.cancel,timeout:t.timeout,state:i(t.promise)},...o))}const s={promise:Promise.all(n),promises:t,done:e=>{t.forEach(t=>t.done(e))},cancel:e=>{t.forEach(t=>t.cancel(e))},each:r,onComplete:o,timeout:()=>{}};return s.timeout=b(!0,s),s}(e):C()}function C(){let e,t;const n=new Promise((n,o)=>{e=n,t=o}),o={promise:n,promises:null,done:e,cancel:t,each:()=>{},onComplete:k(n),timeout:()=>{}};return o.timeout=b(!1,o),o.each=(n,...i)=>{n({value:null,done:e,cancel:t,timeout:o.timeout},...i)},o}function k(e){return function(t,n=null){null===n?e.then(e=>t(e)):e.then(e=>t(e),e=>n(e))}}function b(e,t){let n;return n=e?Promise.all(t.promises.map(e=>e.promise)):t.promise,function(e,o){let i,r=new Promise((t,r)=>{i=setTimeout(()=>{t(o),Promise.resolve(n)},e)});return n.then(()=>clearTimeout(i)),t.onComplete=k(Promise.race([n,r])),t}}function P({message:e,level:t,type:n,logLevel:o}){if(0===o)return null;if(o<t)return null;const i=`[Debug]: ${e}`;switch(n){case"warn":console.warn(i);break;case"error":console.error(i);break;default:console.log(i)}return i}function R(e={},t=P){return function({message:n,type:o,level:i,...r}){const{level:s,type:c,defaultMessageLevel:u}=Object.assign({},{level:1e3,type:"log",defaultMessageLevel:1},e);return o||(o=c),i||(i=u),t({message:n,type:o,level:i,logLevel:s,...r})}}function*L(e,t,n,o){let i=null,r=!0;if(null===e)return yield*o.map(e=>[e,"show"]),void(yield[n,"show"]);if(0!==o.length){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]&&(i=n,!0)),null==i)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>i+1;e--)yield[t[e-1],"hide"];for(let e=i+1;e<o.length;e++)yield[o[e],"show"];yield[n,"show"]}else{if(yield[e,"hide"],t.includes(n)){let e=t.indexOf(n),o=t.filter((t,n)=>n>e);o.reverse(),yield*o.map(e=>[e,"hide"]),r=!1}else{let e=[...t];e.reverse(),yield*e.map(e=>[e,"hide"])}r&&(yield[n,"show"])}}function _(e){return function(t,...n){const{askForPromise:o,deps:i}=e;return function(){const e=o();return t({task:e,dependencies:i()},...n),e.promise.catch(()=>{})}}}return T.sequence=function(e,...t){const n=T(),o=[];const i=function*(e){for(const t of e)yield t}(e);return function e(t,...r){t.done?n.done(o):t.value(...r).then(t=>{o.push(t),e(i.next(),...r,t)})}(i.next(),...t),n},T.all=function(e,...t){const n=T(),o=[],i=e.map((e,n)=>"function"==typeof e?e(...t).then(e=>o[n]=e):e.then(e=>o[n]=e));return Promise.all(i).then(()=>n.done(o)),n},function(e={}){const t=E({errorEventName:"@app-error"}),n=R({level:e.logLevel??1},e=>{const{type:n,logLevel:o}=e;0!==o&&"error"===n&&t.getDependencies().emit("@app-error",e)}),o={currentScene:null,currentParents:null,sceneNames:new Set,scenes:{},opened:!1,jumpStack:[]},i={},r={shortcutMngr:t,findInstructions:L,askForPromise:T,setInstruction:_({askForPromise:T,deps:t.getDependencies}),log:n};return i.hide=function(e,t){return function(n=1){const{askForPromise:o,shortcutMngr:i,setInstruction:r}=e,{currentScene:s,scenes:c}=t,u=o(),l=o();if("function"==typeof c[s].beforeHide){const e=c[s].beforeHide;try{const t=e({done:l.done,dependencies:i.getDependencies()});null!=t&&"function"==typeof t.then&&t.then(l.done).catch(()=>l.done(!1))}catch(e){l.done(!1)}}else l.done(!0);return l.onComplete(e=>{if(!e)return u.done(),u.promise;const l=[],a=[...t.currentParents];i.pause(),l.push(r(c[s].hide));const d="*"===n?a.length:Math.min(n-1,a.length);for(let e=0;e<d;e++){const e=a.pop();l.push(r(c[e].hide))}t.currentScene=a.length>0?a.pop():null,t.currentParents=a,o.sequence(l).onComplete(()=>{i.changeContext(t.currentScene),u.done()})}),u.promise}}(r,o),i.listShortcuts=function(e,t){return function(e){const{scenes:n,sceneNames:o}=t;if(!o.has(e))return null;const{show:i,hide:r,parents:s,beforeHide:c,afterShow:u,...l}=n[e];return Object.keys(l)}}(0,o),i.setScenes=function(e,t){return function(n){const{shortcutMngr:o,log:i}=e;n.forEach(e=>{if(null==e)return;const{name:n,scene:r}=e;if(!n)return void i({message:"Scene name is not defined",level:1,type:"error"});if(null==r)return void i({message:`Scene ${n} is not defined`,level:1,type:"error"});r.parents||(r.parents=[]),t.scenes[n]=r,t.sceneNames.add(n);const{show:s,hide:c,parents:u,...l}=r,a={};a[n]=l,o.load(a)})}}(r,o),i.show=function(e,t){return function({scene:n,options:o={ssr:!1}},...i){const{shortcutMngr:r,askForPromise:s,log:c,findInstructions:u,setInstruction:l}=e,a=s(),d=s(),{opened:p,scenes:f,sceneNames:h,currentScene:m}=t;if(m&&"function"==typeof f[m].beforeHide){const e=f[m].beforeHide;try{const t=e({done:d.done,dependencies:r.getDependencies()});null!=t&&"function"==typeof t.then&&t.then(d.done).catch(()=>d.done(!1))}catch(e){d.done(!1)}}else d.done(!0);return d.onComplete(e=>{if(!e)return a.done(),a.promise;if(!h.has(n))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.currentScene=n,t.currentParents=f[n].parents?[...f[n].parents]:[],r.changeContext(n),a.done(),a.promise;const{show:d,parents:m=[]}=f[n];if(t.currentParents||(t.currentParents=[]),"*"===m[0])return l(d,...i)().then(()=>a.done()),t.currentScene&&t.currentScene!==n&&t.currentParents.push(t.currentScene),t.currentScene=n,r.changeContext(n),a.promise;if(0!==m.length&&!m.every(e=>h.has(e)))return c({message:`Some of '${n}' parent scenes are not set.`,level:1,type:"error"}),a.done(),a.promise;function g([e,n]){if("show"===n)t.currentScene&&(t.currentParents=[...f[t.currentScene].parents]),t.currentScene=e;else{let n="*"===f[e].parents[0]?t.currentParents.pop():f[e].parents.at(-1);t.currentScene=n}return f[e][n]}const v=u(t.currentScene,[...t.currentParents],n,m),y=[];for(let e of v){const t=g(e);y.push(l(t,...i))}s.sequence(y).onComplete(()=>{t.opened=!0,t.currentScene=n,t.currentParents=f[n].parents?[...f[n].parents]:null,r.changeContext(n),"function"==typeof f[n].afterShow&&f[n].afterShow({dependencies:r.getDependencies(),done:()=>{}}),a.done()})}),a.promise}}(r,o),i.jump=function(e,t){return function({scene:n},...o){const i=e.currentScene;return t({scene:n},...o).then(()=>{e.currentScene===n&&e.jumpStack.push(i)}).catch(()=>{})}}(o,i.show),i.jumpBack=function(e,t){return function({hops:n=1}={},...o){for(let t=0;t<n-1;t++)e.jumpStack.pop();if(0===e.jumpStack.length)return;const i=e.jumpStack.pop();return t({scene:i},...o).catch(()=>{})}}(o,i.show),i.jumpsReset=function(e){return function(){e.jumpStack=[]}}(o),i.loadPlugins=async function(e){const t=e.map(e=>`plugin${e}`),n=await Promise.resolve().then(function(){return S});return t.map(e=>n[e])},i.setDependencies=e=>t.setDependencies(e),i.getDependencies=()=>t.getDependencies(),i.setNote=e=>t.setNote(e),i.listScenes=()=>[...o.sceneNames],i.enablePlugin=(e,n)=>t.enablePlugin(e,n),i.disablePlugin=e=>t.disablePlugin(e),i.getState=()=>({scene:o.currentScene,parents:o.currentParents?[...o.currentParents]:o.currentParents,opened:o.opened}),i.emit=(e,...n)=>t.getDependencies().emit(e,...n),i}});
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@peter.naydenov/cuts",
|
|
3
3
|
"description": "SPA scene manager",
|
|
4
|
-
"version": "2.1.
|
|
4
|
+
"version": "2.1.5",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Peter Naydenov",
|
|
7
7
|
"main": "./src/main.js",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"@vitest/coverage-v8": "^4.1.10",
|
|
38
38
|
"rollup": "^4.62.2",
|
|
39
39
|
"typescript": "^7.0.2",
|
|
40
|
-
"vite": "^8.1.
|
|
40
|
+
"vite": "^8.1.4",
|
|
41
41
|
"vitest": "^4.1.10",
|
|
42
42
|
"vue": "^3.5.39"
|
|
43
43
|
},
|
package/src/main.js
CHANGED
|
@@ -36,7 +36,29 @@ import jumpBack from './methods/jumpBack.js'
|
|
|
36
36
|
import jumpsReset from './methods/jumpsReset.js'
|
|
37
37
|
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
/**
|
|
40
|
+
* Cuts
|
|
41
|
+
* @param {CutsConfig} [cfg] - configuration object
|
|
42
|
+
*/
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* @typedef {Object} CutsConfig
|
|
46
|
+
* @property {0|1} [logLevel=1] - Logging level. `1` emits '@app-error' events; `0` silences them silently.
|
|
47
|
+
*/
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* @typedef {'Key'|'Click'|'Form'|'Hover'|'Scroll'} pluginNames
|
|
51
|
+
* @description List of available shortcut plugins.
|
|
52
|
+
*/
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* @typedef {Object} CutsState
|
|
56
|
+
* @property {string|null} scene - current scene name
|
|
57
|
+
* @property {Array.<string>|null} parents - current parent scene names
|
|
58
|
+
* @property {boolean} opened - whether the scene manager is opened
|
|
59
|
+
*/
|
|
60
|
+
|
|
61
|
+
function main ( cfg = {} ) {
|
|
40
62
|
const
|
|
41
63
|
shortcutMngr = shortcuts ({ errorEventName: '@app-error' })
|
|
42
64
|
, logLevel = ( cfg.logLevel ?? 1 )
|
|
@@ -146,14 +168,11 @@ function main ( cfg= {} ) {
|
|
|
146
168
|
*/
|
|
147
169
|
API.disablePlugin = ( pluginName ) => shortcutMngr.disablePlugin ( pluginName )
|
|
148
170
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
* - parents: current parent scene names
|
|
155
|
-
* - opened: boolean indicating if the application is opened
|
|
156
|
-
*/
|
|
171
|
+
/**
|
|
172
|
+
* Get the current state of the application
|
|
173
|
+
* @function getState
|
|
174
|
+
* @returns {CutsState} current scene, parents, and opened flag
|
|
175
|
+
*/
|
|
157
176
|
API.getState = () => ({
|
|
158
177
|
scene : state.currentScene
|
|
159
178
|
// Copy - never leak the live array, or callers mutating it corrupt internal state.
|
package/src/methods/hide.js
CHANGED
|
@@ -6,56 +6,64 @@ function hide ( dependencies, state ) {
|
|
|
6
6
|
/**
|
|
7
7
|
* @function hide
|
|
8
8
|
* @description Hide the current scene and returns to the parent one
|
|
9
|
-
* @param {number|string} endSteps - number of steps to end or '*' to end all scenes to
|
|
10
|
-
* @returns {Promise} - promise that resolves when the process 'end' is completed
|
|
9
|
+
* @param {number|string} [endSteps=1] - number of steps to end; omit or `1` for current scene only; `'*'` to end all scenes to root
|
|
10
|
+
* @returns {Promise<void>} - promise that resolves when the process 'end' is completed
|
|
11
11
|
*/
|
|
12
12
|
return function hide ( endSteps=1 ) {
|
|
13
13
|
const
|
|
14
14
|
{ askForPromise, shortcutMngr, setInstruction } = dependencies
|
|
15
|
-
, { currentScene,
|
|
15
|
+
, { currentScene, scenes } = state
|
|
16
16
|
, hideTask = askForPromise ()
|
|
17
|
-
,
|
|
18
|
-
,
|
|
17
|
+
, unloadTask = askForPromise ()
|
|
18
|
+
, hasBeforeHide = typeof scenes[currentScene].beforeHide === 'function'
|
|
19
19
|
;
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
if ( hasBeforeHide ) { // Execute 'beforeHide' function if exists - same guard 'show' honors when navigating away
|
|
22
|
+
const closingFn = scenes[currentScene].beforeHide;
|
|
23
|
+
try {
|
|
24
|
+
const result = closingFn ({ done:unloadTask.done, dependencies: shortcutMngr.getDependencies() });
|
|
25
|
+
if ( result != null && typeof result.then === 'function' ) {
|
|
26
|
+
result.then ( unloadTask.done ).catch ( () => unloadTask.done ( false ) );
|
|
27
|
+
}
|
|
28
|
+
} catch ( err ) {
|
|
29
|
+
unloadTask.done ( false );
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
else unloadTask.done ( true )
|
|
23
33
|
|
|
24
|
-
|
|
34
|
+
unloadTask.onComplete ( continueHiding => {
|
|
35
|
+
if ( !continueHiding ) {
|
|
36
|
+
// 'beforeHide' returned false - cancel, nothing was torn down or changed
|
|
37
|
+
hideTask.done ()
|
|
38
|
+
return hideTask.promise
|
|
39
|
+
}
|
|
25
40
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
41
|
+
const
|
|
42
|
+
instructions = []
|
|
43
|
+
// Work on a copy of the recorded ancestor chain - it's the source of truth for what to
|
|
44
|
+
// climb back to, including for wildcard-overlay scenes ('*' itself is never stored here,
|
|
45
|
+
// only the real scene name that was current when the overlay was shown).
|
|
46
|
+
, remaining = [ ...state.currentParents ]
|
|
47
|
+
;
|
|
33
48
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
49
|
+
shortcutMngr.pause () // Stop all shortcuts
|
|
50
|
+
instructions.push ( setInstruction ( scenes[currentScene].hide )) // Hiding the current scene is always at least 1 step
|
|
51
|
+
|
|
52
|
+
const ancestorsToHide = ( endSteps === '*' ) ? remaining.length : Math.min ( endSteps - 1, remaining.length )
|
|
53
|
+
for ( let i = 0; i < ancestorsToHide; i++ ) {
|
|
54
|
+
const name = remaining.pop ()
|
|
55
|
+
instructions.push ( setInstruction ( scenes[name].hide ))
|
|
56
|
+
}
|
|
41
57
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
// Climb to the parent of the scene just hidden - same technique 'show' uses for its 'hide' steps.
|
|
45
|
-
// A wildcard overlay isn't climbing its own declared parent ('*' isn't a real scene) - and
|
|
46
|
-
// there's no reliable way to recover what it originally covered once it's this deep in the
|
|
47
|
-
// chain, so fall back to treating it as the end of the chain rather than crashing.
|
|
48
|
-
state.currentScene = ( scenes[name].parents[0] === '*' )
|
|
49
|
-
? null
|
|
50
|
-
: ( scenes[name].parents.at ( -1 ) ?? null )
|
|
51
|
-
state.currentParents = state.currentScene ? scenes[state.currentScene].parents : []
|
|
52
|
-
})
|
|
58
|
+
state.currentScene = remaining.length > 0 ? remaining.pop () : null
|
|
59
|
+
state.currentParents = remaining
|
|
53
60
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
61
|
+
const goingTask = askForPromise.sequence ( instructions );
|
|
62
|
+
goingTask.onComplete ( () => {
|
|
63
|
+
shortcutMngr.changeContext ( state.currentScene ) // If state.currentScene is null, then all shortcuts are switched off and currentContext is null
|
|
64
|
+
hideTask.done ()
|
|
65
|
+
})
|
|
66
|
+
}) // unloadTask onComplete
|
|
59
67
|
return hideTask.promise
|
|
60
68
|
}} // hide func.
|
|
61
69
|
|
|
@@ -63,4 +71,3 @@ return function hide ( endSteps=1 ) {
|
|
|
63
71
|
|
|
64
72
|
export default hide
|
|
65
73
|
|
|
66
|
-
|
package/src/methods/jump.js
CHANGED
|
@@ -8,8 +8,13 @@ function jump ( state, show ) {
|
|
|
8
8
|
* @returns {Promise} - promise that resolves when the jump is completed
|
|
9
9
|
*/
|
|
10
10
|
function jump ( { scene }, ...args ) {
|
|
11
|
-
|
|
12
|
-
return show ( { scene }, ...args )
|
|
11
|
+
const previousScene = state.currentScene
|
|
12
|
+
return show ( { scene }, ...args ).then ( () => {
|
|
13
|
+
// Only record the jump if it actually landed - 'show' silently no-ops on a
|
|
14
|
+
// blocked (beforeHide) or invalid navigation, and pushing anyway would leave
|
|
15
|
+
// a phantom entry that desyncs jumpBack() from what actually happened.
|
|
16
|
+
if ( state.currentScene === scene ) state.jumpStack.push ( previousScene )
|
|
17
|
+
}).catch ( () => {} ) // Swallow rejections so they don't become unhandled
|
|
13
18
|
}
|
|
14
19
|
return jump
|
|
15
20
|
} // jump func.
|
package/src/methods/jumpBack.js
CHANGED
|
@@ -7,13 +7,13 @@ function jumpBack ( state, show ) {
|
|
|
7
7
|
* @param {Array} [args] - arguments to pass to the scene method
|
|
8
8
|
* @returns {Promise|undefined} - promise that resolves when the jump back is completed, or undefined if no scenes in stack
|
|
9
9
|
*/
|
|
10
|
-
function jumpBack ({hops}={
|
|
10
|
+
function jumpBack ( { hops = 1 } = {}, ...args ) {
|
|
11
11
|
for ( let i = 0; i < hops-1; i++ ) {
|
|
12
12
|
state.jumpStack.pop ()
|
|
13
13
|
}
|
|
14
14
|
if ( state.jumpStack.length === 0 ) return
|
|
15
15
|
const lastScene = state.jumpStack.pop ();
|
|
16
|
-
return show ( { scene : lastScene }, ...args )
|
|
16
|
+
return show ( { scene : lastScene }, ...args ).catch ( () => {} ) // Swallow rejections so they don't become unhandled
|
|
17
17
|
}
|
|
18
18
|
return jumpBack
|
|
19
19
|
} // jumpBack func.
|
package/src/methods/setScenes.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
/**
|
|
9
9
|
* @typedef {Object} SceneObject
|
|
10
10
|
* @property {function({task: AskObject, dependencies: *}): void} show - load interface and prerequisites for the scene;
|
|
11
|
-
* @property {function():
|
|
11
|
+
* @property {function({dependencies: *, done: function}):void} [afterShow] - run after the scene is shown. Optional. Fire-and-forget - its return value is not used, and it cannot cancel or affect the already-completed 'show';
|
|
12
12
|
* @property {function({task: AskObject, dependencies: *}): void} hide - Reverse the settings from 'show';
|
|
13
13
|
* @property {function():void} [beforeHide] - Run before scene is hidden. Optional;
|
|
14
14
|
* @property {Array.<string>} [parents] - list of parent scene names.
|
package/src/methods/show.js
CHANGED
|
@@ -22,11 +22,18 @@ function show ( dependencies, state ) {
|
|
|
22
22
|
, hasBeforeHide = currentScene && (typeof scenes[currentScene].beforeHide === 'function')
|
|
23
23
|
;
|
|
24
24
|
|
|
25
|
-
if ( hasBeforeHide ) { // Execute '
|
|
25
|
+
if ( hasBeforeHide ) { // Execute 'beforeHide' function if exists
|
|
26
26
|
const closingFn = scenes[currentScene].beforeHide;
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
try {
|
|
28
|
+
const result = closingFn ({ done:unloadTask.done, dependencies: shortcutMngr.getDependencies() });
|
|
29
|
+
// If beforeHide returns a Promise, resolve it and pass the result to unloadTask.done
|
|
30
|
+
// so async blocking logic works correctly (e.g. confirm dialog → done(false)).
|
|
31
|
+
if ( result != null && typeof result.then === 'function' ) {
|
|
32
|
+
result.then ( unloadTask.done ).catch ( () => unloadTask.done ( false ) );
|
|
33
|
+
}
|
|
34
|
+
} catch ( err ) {
|
|
35
|
+
unloadTask.done ( false );
|
|
36
|
+
}
|
|
30
37
|
} // if currentScene
|
|
31
38
|
else unloadTask.done ( true )
|
|
32
39
|
|
|
@@ -53,6 +60,9 @@ function show ( dependencies, state ) {
|
|
|
53
60
|
// Executes only once when the scene manager is started
|
|
54
61
|
state.opened = true
|
|
55
62
|
state.currentScene = requestedScene
|
|
63
|
+
// The server-rendered scene's ancestors are assumed already rendered too -
|
|
64
|
+
// record them, or navigating away later won't know to hide them.
|
|
65
|
+
state.currentParents = scenes[requestedScene].parents ? [ ...scenes[requestedScene].parents ] : []
|
|
56
66
|
shortcutMngr.changeContext ( requestedScene )
|
|
57
67
|
showTask.done ()
|
|
58
68
|
return showTask.promise
|
|
@@ -65,7 +75,11 @@ function show ( dependencies, state ) {
|
|
|
65
75
|
if ( parents[0] === '*' ) {
|
|
66
76
|
const overlayTask = setInstruction(show, ...args)()
|
|
67
77
|
overlayTask.then ( () => showTask.done () )
|
|
68
|
-
|
|
78
|
+
// Only remember a real underlying scene - pushing 'null' as a placeholder
|
|
79
|
+
// makes later navigation treat it as a scene name to hide, and crash.
|
|
80
|
+
// Re-showing the SAME overlay that's already current must not push it onto
|
|
81
|
+
// its own ancestor chain either, or hide() later climbs back onto itself.
|
|
82
|
+
if ( state.currentScene && state.currentScene !== requestedScene ) state.currentParents.push ( state.currentScene )
|
|
69
83
|
state.currentScene = requestedScene
|
|
70
84
|
shortcutMngr.changeContext ( requestedScene ) // Activate the overlay scene's own shortcuts
|
|
71
85
|
return showTask.promise
|
|
@@ -101,7 +115,10 @@ function show ( dependencies, state ) {
|
|
|
101
115
|
} // getStep func.
|
|
102
116
|
|
|
103
117
|
const
|
|
104
|
-
|
|
118
|
+
// Snapshot - findInstructions is a lazy generator, and getStep (in the loop below)
|
|
119
|
+
// mutates state.currentParents in place; without a copy, that mutation corrupts
|
|
120
|
+
// the generator's still-pending reads of the very array it was given.
|
|
121
|
+
g = findInstructions ( state.currentScene, [ ...state.currentParents ], requestedScene, parents )
|
|
105
122
|
, instructions = []
|
|
106
123
|
;
|
|
107
124
|
|
package/src/setInstruction.js
CHANGED
|
@@ -13,7 +13,11 @@ return function setInstruction ( fn, ...args ) {
|
|
|
13
13
|
return function applyInstruction () {
|
|
14
14
|
const task = askForPromise ();
|
|
15
15
|
fn ({ task, dependencies:deps() }, ...args )
|
|
16
|
-
|
|
16
|
+
// Swallow unhandled rejections from scene functions — the promise resolves
|
|
17
|
+
// as normal (via task.done() inside the scene), but if the scene throws or
|
|
18
|
+
// returns a rejected promise without catching, this prevents an unhandled
|
|
19
|
+
// rejection at the process level.
|
|
20
|
+
return task.promise.catch ( () => {} )
|
|
17
21
|
} // applyInstruction func.
|
|
18
22
|
}} // setInstruction func.
|
|
19
23
|
|