From 1d6f3a37cafa3c7347514b694a8f44b8fa183054 Mon Sep 17 00:00:00 2001 From: Julian Waller Date: Tue, 22 Oct 2024 14:59:43 +0100 Subject: [PATCH] wip: update sorensen and re-patch --- ...mation-sorensen-npm-1.4.3-a11a53b994.patch | 22 - ...mation-sorensen-npm-1.5.0-88bfc56810.patch | 651 ++++++++++++++++++ apps/app/package.json | 2 +- apps/app/src/react/App.tsx | 29 +- .../rundown/GroupView/GroupView.tsx | 8 +- .../components/rundown/GroupView/PartView.tsx | 18 +- .../rundown/GroupView/TimelineObject.tsx | 22 +- .../react/components/rundown/RundownView.tsx | 10 +- .../sidebar/SidebarResourceLibrary.tsx | 4 +- yarn.lock | 18 +- 10 files changed, 706 insertions(+), 78 deletions(-) delete mode 100644 .yarn/patches/@sofie-automation-sorensen-npm-1.4.3-a11a53b994.patch create mode 100644 .yarn/patches/@sofie-automation-sorensen-npm-1.5.0-88bfc56810.patch diff --git a/.yarn/patches/@sofie-automation-sorensen-npm-1.4.3-a11a53b994.patch b/.yarn/patches/@sofie-automation-sorensen-npm-1.4.3-a11a53b994.patch deleted file mode 100644 index 098e89b3..00000000 --- a/.yarn/patches/@sofie-automation-sorensen-npm-1.4.3-a11a53b994.patch +++ /dev/null @@ -1,22 +0,0 @@ -diff --git a/dist/index.d.ts b/dist/index.d.ts -index 69f4d81b0119e47ac0d81da69f6b3c1de253f570..500de075f88b7fe387dae5dbef2f04534a125d08 100644 ---- a/dist/index.d.ts -+++ b/dist/index.d.ts -@@ -143,7 +143,7 @@ declare function addEventListener(event: 'layoutchange', handler: EventHandler): - declare function addEventListener(event: 'keycancel', handler: EventHandlerWithArgs): void; - declare function removeEventListener(event: 'layoutchange', handler: EventHandler): void; - declare function removeEventListener(event: 'keycancel', handler: EventHandlerWithArgs): void; --declare const sorensen: { -+export const sorensen: { - init: typeof init; - destroy: typeof destroy; - getCodeForKey: typeof getCodeForKey; -diff --git a/dist/sorensen.js b/dist/sorensen.js -index 4097b72c36185e3335a3159f318a9f3100c24934..999153171cf7f57fd624fc3e68673d71f1f99a5c 100644 ---- a/dist/sorensen.js -+++ b/dist/sorensen.js -@@ -1,2 +1,2 @@ --!function(e,n){"object"==typeof exports&&"object"==typeof module?module.exports=n():"function"==typeof define&&define.amd?define("sorensen",[],n):"object"==typeof exports?exports.sorensen=n():e.sorensen=n()}(window,(function(){return function(e){var n={};function t(o){if(n[o])return n[o].exports;var i=n[o]={i:o,l:!1,exports:{}};return e[o].call(i.exports,i,i.exports,t),i.l=!0,i.exports}return t.m=e,t.c=n,t.d=function(e,n,o){t.o(e,n)||Object.defineProperty(e,n,{enumerable:!0,get:o})},t.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},t.t=function(e,n){if(1&n&&(e=t(e)),8&n)return e;if(4&n&&"object"==typeof e&&e&&e.__esModule)return e;var o=Object.create(null);if(t.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:e}),2&n&&"string"!=typeof e)for(var i in e)t.d(o,i,function(n){return e[n]}.bind(null,i));return o},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},t.p="",t(t.s=0)}([function(e,n,t){var o,i,r;!function(a){if("object"==typeof e.exports){var d=a(t(1),n);void 0!==d&&(e.exports=d)}else i=[t,n],void 0===(r="function"==typeof(o=a)?o.apply(n,i):o)||(e.exports=r)}((function(e,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0}),n.VIRTUAL_ANY_POSITION_KEYS=void 0;let t=!1,o=void 0,i=[],r=[],a=[],d=[],c=[],l=!1;let u=2e3;const f=Symbol("sorensen_immediatePropagationStopped"),s=Symbol("sorensen_stopImmediatePropagation");const g=["ShiftLeft","ShiftRight","ControlLeft","ControlRight","AltLeft","AltRight","MetaLeft","MetaRight","OSLeft","OSRight"];n.VIRTUAL_ANY_POSITION_KEYS={Shift:["ShiftLeft","ShiftRight"],Control:["ControlLeft","ControlRight"],Ctrl:["ControlLeft","ControlRight"],Alt:["AltLeft","AltRight"],Meta:["MetaLeft","MetaRight"],AnyEnter:["Enter","NumpadEnter"],Option:["AltLeft","AltRight"],Command:["OSLeft","OSRight"],Windows:["OSLeft","OSRight"],Accel:/(Mac|iPhone|iPod|iPad)/i.test(navigator.platform)?["OSLeft","OSRight"]:["ControlLeft","ControlRight"]};const v={};function h(e){return e.split(/\s+/).filter(Boolean).map(e=>e.split("+").filter(Boolean))}function p(e){return e.map(e=>e.join("+")).join(" ")}function b(e,t,o,i){var r;const a=o.ordered?function(e,t,o,i){const r="modifiersFirst"===(null==o?void 0:o.ordered);let a=-1,d=-1;for(let o=0;o=0&&c>a){o=!0,r&&g.includes(e[n])?d=c:a=c,i.push(e[n]);break}}if(!o)return!1}else{const n=t.indexOf(e[o],a+1);if(n<0||n<=a)return!1;r&&g.includes(e[o])?d=n:a=n,i.push(e[o])}if(r&&a>=0&&d>a)return!1}return!0}(e,t,o,i):function(e,t,o,i){for(let o=0;o{n[f]||(n[f]=!0,n[s]())}}))}function w(e,n,t){!1!==e.preventDefaultPartials&&y(e,n)&&(a=[...a,...t])}function E(e,n,t){const o=d.length;i.forEach(i=>{var a;const l=[];b(i.combo[0],n?[...c,e]:c,i,l)&&(null!==(a=i.up)&&void 0!==a&&a)===n&&(0!==o&&!1!==i.exclusive||(1===i.combo.length?m(i,t,0):(d.push({binding:i,note:1}),r=[...r,...c]))),w(i,t,l)})}function L(e,n,t){const o=[];d.forEach(i=>{var a;if((null!==(a=i.binding.up)&&void 0!==a&&a)!==n)return;if(i.binding.combo.length<=i.note)return void o.push(i);const d=[];if(b(i.binding.combo[i.note],n?[...c,e]:c,i.binding,d)){if(i.note=i.note+1,i.binding.combo.length===i.note)return void m(i.binding,t,i.note);r=[...r,...c]}else n&&r.includes(e)?r=r.filter(n=>n!==e):function(e,n){return e.includes(n)||n in v&&e.includes(v[n])}(i.binding.combo[i.note],e)||!i.binding.modifiersPoisonChord&&g.includes(e)||o.push(i);w(i.binding,t,d)}),d=d.filter(e=>!o.includes(e))}function S(){d=d.filter(e=>e.note{e[1].forEach(n=>v[n]=e[0])});let _=void 0;function A(){_&&clearTimeout(_),_=void 0}function P(e){c=c.filter(n=>n!==e.code),l||(L((e=O(e)).code,!0,e),E(e.code,!0,e)),S(),A(),u>0&&(_=setTimeout(()=>{d.length=0},u)),0===c.length&&(r.length=0),function(e){0===c.length&&(a.length=0),e&&(a=a.filter(n=>n!==e.code))}(e),l&&0===c.length&&(l=!1)}function I(e){e.repeat||(c.push(e.code),l||(L((e=O(e)).code,!1,e),E(e.code,!1,e),function(e,n){const t=[];d.forEach(e=>{if(!e.binding.preventDefaultDown)return;if(!y(e.binding,n))return;if(e.note>e.binding.combo.length)return;const o=[];b(e.binding.combo[e.note-1],c,e.binding,o)&&(n.defaultPreventedDown=!0,t.push(...o))}),i.forEach(e=>{if(!e.preventDefaultDown)return;if(!y(e,n))return;if(1!==e.combo.length)return;const o=[];b(e.combo[0],c,e,o)&&(n.defaultPreventedDown=!0,t.push(...o))}),a=[...a,...Array.from(new Set(t))]}(e.code,e)),S(),A()),a.includes(e.code)&&function(e){e.preventDefault()}(e)}function R(){"visibilityState"in document&&"hidden"===document.visibilityState&&k()}function C(){k()}async function T(){if("keyboard"in navigator&&navigator.keyboard&&"function"==typeof navigator.keyboard.getLayoutMap)try{o=await navigator.keyboard.getLayoutMap(),j("layoutchange")}catch(e){console.error("Could not get keyboard layout map.",e)}}function k(){const e=c.slice();c.length=0,e.forEach(e=>j("keycancel",{code:e})),l=!1}const N={};function j(e,n){Array.isArray(N[e])&&N[e].forEach(e=>{try{e(n)}catch(e){console.error(e)}})}const x={init:async function(e){var n;if(t)throw new Error("Sørensen already initialized.");u=null!==(n=null==e?void 0:e.chordTimeout)&&void 0!==n?n:2e3,window.addEventListener("keyup",P,{passive:!1,capture:!0}),window.addEventListener("keydown",I,{passive:!1,capture:!0}),window.addEventListener("visibilitychange",R),window.addEventListener("blur",C),window.addEventListener("pagehide",C),"keyboard"in navigator&&navigator.keyboard&&"function"==typeof navigator.keyboard.addEventListener&&navigator.keyboard.addEventListener("layoutchange",T),await T(),i=[],c=[],d=[],t=!0},destroy:async function(){if(!t)throw new Error("Sørensen already destroyed.");window.removeEventListener("keyup",P),window.removeEventListener("keydown",I),window.removeEventListener("visibilitychange",R),window.removeEventListener("blur",C),window.removeEventListener("pagehide",C),"keyboard"in navigator&&navigator.keyboard&&"function"==typeof navigator.keyboard.removeEventListener&&navigator.keyboard.removeEventListener("layoutchange",T),t=!1},getCodeForKey:function(e){if(1===e.length&&(e=e.toLowerCase()),!o)return e.match(/^\d+$/)?"Digit"+e:e.match(/^\w$/)?"Key"+e:""+e;for(let[n,t]of o.entries())if(t===e)return n},getKeyForCode:function(e){if(o){let n=o.get(e);return void 0===n&&(n=e.replace(/^Key/,"").replace(/^Digit(?=\d+)/,""),1===n.length&&(n=n.toLowerCase())),n}{let n=e.replace(/^Key/,"").replace(/^Digit(?=\d+)/,"");return 1===n.length&&(n=n.toLowerCase()),n}},getPressedKeys:function(){return[...c]},bind:function(e,n,o){if(!t)throw new Error("Sørensen needs to be initialized before binding any combos.");Array.isArray(e)||(e=[e]),e.forEach(e=>{const t=h(e);if(!(null==t?void 0:t.length)||!t[0].length)throw new Error("Combo needs to have at least a single key in it");(null==o?void 0:o.prepend)?i.unshift({combo:t,listener:n,...o}):i.push({combo:t,listener:n,...o})})},unbind:function(e,n,t){let o=[],r=p(h(e));i.forEach(e=>{n&&e.listener!==n||p(e.combo)!==r||void 0!==t&&t!==e.tag||o.push(e)}),i=i.filter(e=>!o.includes(e))},poison:function(){d.length=0,l=!0},addEventListener:function(e,n){void 0===N[e]&&(N[e]=[]),N[e].push(n)},removeEventListener:function(e,n){Array.isArray(N[e])&&(N[e]=N[e].filter(e=>e!==n))}};window&&(window.sorensen=x),n.default=x}))},function(e,n){function t(e){var n=new Error("Cannot find module '"+e+"'");throw n.code="MODULE_NOT_FOUND",n}t.keys=function(){return[]},t.resolve=t,e.exports=t,t.id=1}]).default})); -+!function(e,n){"object"==typeof exports&&"object"==typeof module?module.exports=n():"function"==typeof define&&define.amd?define("sorensen",[],n):"object"==typeof exports?exports.sorensen=n():e.sorensen=n()}(window,(function(){return function(e){var n={};function t(o){if(n[o])return n[o].exports;var i=n[o]={i:o,l:!1,exports:{}};return e[o].call(i.exports,i,i.exports,t),i.l=!0,i.exports}return t.m=e,t.c=n,t.d=function(e,n,o){t.o(e,n)||Object.defineProperty(e,n,{enumerable:!0,get:o})},t.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},t.t=function(e,n){if(1&n&&(e=t(e)),8&n)return e;if(4&n&&"object"==typeof e&&e&&e.__esModule)return e;var o=Object.create(null);if(t.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:e}),2&n&&"string"!=typeof e)for(var i in e)t.d(o,i,function(n){return e[n]}.bind(null,i));return o},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},t.p="",t(t.s=0)}([function(e,n,t){var o,i,r;!function(a){if("object"==typeof e.exports){var d=a(t(1),n);void 0!==d&&(e.exports=d)}else i=[t,n],void 0===(r="function"==typeof(o=a)?o.apply(n,i):o)||(e.exports=r)}((function(e,n){"use strict";Object.defineProperty(n,"__esModule",{value:!0}),n.VIRTUAL_ANY_POSITION_KEYS=void 0;let t=!1,o=void 0,i=[],r=[],a=[],d=[],c=[],l=!1;let u=2e3;const f=Symbol("sorensen_immediatePropagationStopped"),s=Symbol("sorensen_stopImmediatePropagation");const g=["ShiftLeft","ShiftRight","ControlLeft","ControlRight","AltLeft","AltRight","MetaLeft","MetaRight","OSLeft","OSRight"];n.VIRTUAL_ANY_POSITION_KEYS={Shift:["ShiftLeft","ShiftRight"],Control:["ControlLeft","ControlRight"],Ctrl:["ControlLeft","ControlRight"],Alt:["AltLeft","AltRight"],Meta:["MetaLeft","MetaRight"],AnyEnter:["Enter","NumpadEnter"],Option:["AltLeft","AltRight"],Command:["OSLeft","OSRight"],Windows:["OSLeft","OSRight"],Accel:/(Mac|iPhone|iPod|iPad)/i.test(navigator.platform)?["OSLeft","OSRight"]:["ControlLeft","ControlRight"]};const v={};function h(e){return e.split(/\s+/).filter(Boolean).map(e=>e.split("+").filter(Boolean))}function p(e){return e.map(e=>e.join("+")).join(" ")}function b(e,t,o,i){var r;const a=o.ordered?function(e,t,o,i){const r="modifiersFirst"===(null==o?void 0:o.ordered);let a=-1,d=-1;for(let o=0;o=0&&c>a){o=!0,r&&g.includes(e[n])?d=c:a=c,i.push(e[n]);break}}if(!o)return!1}else{const n=t.indexOf(e[o],a+1);if(n<0||n<=a)return!1;r&&g.includes(e[o])?d=n:a=n,i.push(e[o])}if(r&&a>=0&&d>a)return!1}return!0}(e,t,o,i):function(e,t,o,i){for(let o=0;o{n[f]||(n[f]=!0,n[s]())}}))}function w(e,n,t){!1!==e.preventDefaultPartials&&y(e,n)&&(a=[...a,...t])}function E(e,n,t){const o=d.length;i.forEach(i=>{var a;const l=[];b(i.combo[0],n?[...c,e]:c,i,l)&&(null!==(a=i.up)&&void 0!==a&&a)===n&&(0!==o&&!1!==i.exclusive||(1===i.combo.length?m(i,t,0):(d.push({binding:i,note:1}),r=[...r,...c]))),w(i,t,l)})}function L(e,n,t){const o=[];d.forEach(i=>{var a;if((null!==(a=i.binding.up)&&void 0!==a&&a)!==n)return;if(i.binding.combo.length<=i.note)return void o.push(i);const d=[];if(b(i.binding.combo[i.note],n?[...c,e]:c,i.binding,d)){if(i.note=i.note+1,i.binding.combo.length===i.note)return void m(i.binding,t,i.note);r=[...r,...c]}else n&&r.includes(e)?r=r.filter(n=>n!==e):function(e,n){return e.includes(n)||n in v&&e.includes(v[n])}(i.binding.combo[i.note],e)||!i.binding.modifiersPoisonChord&&g.includes(e)||o.push(i);w(i.binding,t,d)}),d=d.filter(e=>!o.includes(e))}function S(){d=d.filter(e=>e.note{e[1].forEach(n=>v[n]=e[0])});let _=void 0;function A(){_&&clearTimeout(_),_=void 0}function P(e){c=c.filter(n=>n!==e.code),l||(L((e=O(e)).code,!0,e),E(e.code,!0,e)),S(),A(),u>0&&(_=setTimeout(()=>{d.length=0},u)),0===c.length&&(r.length=0),function(e){0===c.length&&(a.length=0),e&&(a=a.filter(n=>n!==e.code))}(e),l&&0===c.length&&(l=!1)}function I(e){e.repeat||(c.push(e.code),l||(L((e=O(e)).code,!1,e),E(e.code,!1,e),function(e,n){const t=[];d.forEach(e=>{if(!e.binding.preventDefaultDown)return;if(!y(e.binding,n))return;if(e.note>e.binding.combo.length)return;const o=[];b(e.binding.combo[e.note-1],c,e.binding,o)&&(n.defaultPreventedDown=!0,t.push(...o))}),i.forEach(e=>{if(!e.preventDefaultDown)return;if(!y(e,n))return;if(1!==e.combo.length)return;const o=[];b(e.combo[0],c,e,o)&&(n.defaultPreventedDown=!0,t.push(...o))}),a=[...a,...Array.from(new Set(t))]}(e.code,e)),S(),A()),a.includes(e.code)&&function(e){e.preventDefault()}(e)}function R(){"visibilityState"in document&&"hidden"===document.visibilityState&&k()}function C(){k()}async function T(){if("keyboard"in navigator&&navigator.keyboard&&"function"==typeof navigator.keyboard.getLayoutMap)try{o=await navigator.keyboard.getLayoutMap(),j("layoutchange")}catch(e){console.error("Could not get keyboard layout map.",e)}}function k(){const e=c.slice();c.length=0,e.forEach(e=>j("keycancel",{code:e})),l=!1}const N={};function j(e,n){Array.isArray(N[e])&&N[e].forEach(e=>{try{e(n)}catch(e){console.error(e)}})}const x={init:async function(e){var n;if(t)throw new Error("Sørensen already initialized.");u=null!==(n=null==e?void 0:e.chordTimeout)&&void 0!==n?n:2e3,window.addEventListener("keyup",P,{passive:!1,capture:!0}),window.addEventListener("keydown",I,{passive:!1,capture:!0}),window.addEventListener("visibilitychange",R),window.addEventListener("blur",C),window.addEventListener("pagehide",C),"keyboard"in navigator&&navigator.keyboard&&"function"==typeof navigator.keyboard.addEventListener&&navigator.keyboard.addEventListener("layoutchange",T),await T(),i=[],c=[],d=[],t=!0},destroy:async function(){if(!t)throw new Error("Sørensen already destroyed.");window.removeEventListener("keyup",P),window.removeEventListener("keydown",I),window.removeEventListener("visibilitychange",R),window.removeEventListener("blur",C),window.removeEventListener("pagehide",C),"keyboard"in navigator&&navigator.keyboard&&"function"==typeof navigator.keyboard.removeEventListener&&navigator.keyboard.removeEventListener("layoutchange",T),t=!1},getCodeForKey:function(e){if(1===e.length&&(e=e.toLowerCase()),!o)return e.match(/^\d+$/)?"Digit"+e:e.match(/^\w$/)?"Key"+e:""+e;for(let[n,t]of o.entries())if(t===e)return n},getKeyForCode:function(e){if(o){let n=o.get(e);return void 0===n&&(n=e.replace(/^Key/,"").replace(/^Digit(?=\d+)/,""),1===n.length&&(n=n.toLowerCase())),n}{let n=e.replace(/^Key/,"").replace(/^Digit(?=\d+)/,"");return 1===n.length&&(n=n.toLowerCase()),n}},getPressedKeys:function(){return[...c]},bind:function(e,n,o){if(!t)throw new Error("Sørensen needs to be initialized before binding any combos.");Array.isArray(e)||(e=[e]),e.forEach(e=>{const t=h(e);if(!(null==t?void 0:t.length)||!t[0].length)throw new Error("Combo needs to have at least a single key in it");(null==o?void 0:o.prepend)?i.unshift({combo:t,listener:n,...o}):i.push({combo:t,listener:n,...o})})},unbind:function(e,n,t){let o=[],r=p(h(e));i.forEach(e=>{n&&e.listener!==n||p(e.combo)!==r||void 0!==t&&t!==e.tag||o.push(e)}),i=i.filter(e=>!o.includes(e))},poison:function(){d.length=0,l=!0},addEventListener:function(e,n){void 0===N[e]&&(N[e]=[]),N[e].push(n)},removeEventListener:function(e,n){Array.isArray(N[e])&&(N[e]=N[e].filter(e=>e!==n))}};window&&(window.sorensen=x),n.sorensen=x,n.default=x}))},function(e,n){function t(e){var n=new Error("Cannot find module '"+e+"'");throw n.code="MODULE_NOT_FOUND",n}t.keys=function(){return[]},t.resolve=t,e.exports=t,t.id=1}]).default})); - //# sourceMappingURL=sorensen.js.map -\ No newline at end of file diff --git a/.yarn/patches/@sofie-automation-sorensen-npm-1.5.0-88bfc56810.patch b/.yarn/patches/@sofie-automation-sorensen-npm-1.5.0-88bfc56810.patch new file mode 100644 index 00000000..262f1b46 --- /dev/null +++ b/.yarn/patches/@sofie-automation-sorensen-npm-1.5.0-88bfc56810.patch @@ -0,0 +1,651 @@ +diff --git a/dist/index.js b/dist/index.js +new file mode 100644 +index 0000000000000000000000000000000000000000..b92a71398f3c7fca7ef02b9e4244b12cfab62b93 +--- /dev/null ++++ b/dist/index.js +@@ -0,0 +1,627 @@ ++/// ++(function (factory) { ++ if (typeof module === "object" && typeof module.exports === "object") { ++ var v = factory(require, exports); ++ if (v !== undefined) module.exports = v; ++ } ++ else if (typeof define === "function" && define.amd) { ++ define(["require", "exports"], factory); ++ } ++})(function (require, exports) { ++ "use strict"; ++ Object.defineProperty(exports, "__esModule", { value: true }); ++ exports.Sorensen = exports.VIRTUAL_ANY_POSITION_KEYS = void 0; ++ let initialized = false; ++ let keyboardLayoutMap = undefined; ++ let bound = []; ++ let keyUpIgnoreKeys = []; ++ let keyRepeatIgnoreKeys = []; ++ let chordsInProgress = []; ++ let keysDown = []; ++ let poisoned = false; ++ const DEFAULT_CHORD_TIMEOUT = 2000; ++ let CHORD_TIMEOUT = DEFAULT_CHORD_TIMEOUT; ++ const SORENSEN_IMMEDIATE_PROPAGATION_STOPPED = Symbol('sorensen_immediatePropagationStopped'); ++ const SORENSEN_STOP_IMMEDIATE_PROPAGATION = Symbol('sorensen_stopImmediatePropagation'); ++ function isMac() { ++ return /(Mac|iPhone|iPod|iPad)/i.test(navigator.platform); ++ } ++ const MODIFIER_KEYS = [ ++ 'ShiftLeft', ++ 'ShiftRight', ++ 'ControlLeft', ++ 'ControlRight', ++ 'AltLeft', ++ 'AltRight', ++ 'MetaLeft', ++ 'MetaRight', ++ 'OSLeft', ++ 'OSRight', ++ ]; ++ /** ++ * Special meta-codes that can be used to match for "any" modifer key, like matching for both ShiftLeft and ShiftRight. ++ */ ++ exports.VIRTUAL_ANY_POSITION_KEYS = { ++ Shift: ['ShiftLeft', 'ShiftRight'], ++ Control: ['ControlLeft', 'ControlRight'], ++ Ctrl: ['ControlLeft', 'ControlRight'], ++ Alt: ['AltLeft', 'AltRight'], ++ Meta: ['MetaLeft', 'MetaRight'], ++ AnyEnter: ['Enter', 'NumpadEnter'], ++ Option: ['AltLeft', 'AltRight'], ++ Command: ['OSLeft', 'OSRight'], ++ Windows: ['OSLeft', 'OSRight'], ++ Accel: isMac() ? ['OSLeft', 'OSRight'] : ['ControlLeft', 'ControlRight'], ++ }; ++ const INVERSE_VIRTUAL_ANY_POSITION_KEYS = {}; ++ Object.entries(exports.VIRTUAL_ANY_POSITION_KEYS).forEach((entry) => { ++ entry[1].forEach((code) => (INVERSE_VIRTUAL_ANY_POSITION_KEYS[code] = entry[0])); ++ }); ++ function parseCombo(combo) { ++ return combo ++ .split(/\s+/) ++ .filter(Boolean) ++ .map((note) => note.split('+').filter(Boolean)); ++ } ++ function stringifyCombo(combo) { ++ return combo.map((note) => note.join('+')).join(' '); ++ } ++ /** ++ * Bind a combo or set of combos to a given event listener. ++ * ++ * @param {(string | string[])} combo A combo or chord to be bound, specified using keybaord button code values. ++ * Whitespace separates multiple notes in a chord. `+` means key combinations. ++ * @param {(e: EnchancedKeyboardEvent) => void} listener ++ * @param {BindOptions} [options] ++ */ ++ function bind(combo, listener, options) { ++ if (!initialized) { ++ throw new Error('Sørensen needs to be initialized before binding any combos.'); ++ } ++ if (!Array.isArray(combo)) { ++ combo = [combo]; ++ } ++ combo.forEach((variant) => { ++ const item = parseCombo(variant); ++ if (!(item === null || item === void 0 ? void 0 : item.length) || !item[0].length) { ++ throw new Error('Combo needs to have at least a single key in it'); ++ } ++ if (options === null || options === void 0 ? void 0 : options.prepend) { ++ bound.unshift({ ++ combo: item, ++ listener, ++ ...options, ++ }); ++ } ++ else { ++ bound.push({ ++ combo: item, ++ listener, ++ ...options, ++ }); ++ } ++ }); ++ } ++ /** ++ * Unbind a combo from a given event listener. If a `tag` is provided, only bindings with a strictly equal binding will ++ * be removed ++ * ++ * @param {string} combo A combo bound to the `listener`. ++ * @param {(e: EnchancedKeyboardEvent) => void} [listener] ++ */ ++ function unbind(combo, listener, tag) { ++ let bindingsToUnbind = []; ++ let normalizedCombo = stringifyCombo(parseCombo(combo)); ++ bound.forEach((binding) => { ++ if ((!listener || binding.listener === listener) && stringifyCombo(binding.combo) === normalizedCombo) { ++ if (tag === undefined || tag === binding.tag) { ++ bindingsToUnbind.push(binding); ++ } ++ } ++ }); ++ bound = bound.filter((binding) => !bindingsToUnbind.includes(binding)); ++ } ++ function noteIncludesKey(note, key) { ++ return (note.includes(key) || ++ (key in INVERSE_VIRTUAL_ANY_POSITION_KEYS && note.includes(INVERSE_VIRTUAL_ANY_POSITION_KEYS[key]))); ++ } ++ function matchNote(note, keysToMatch, options, outIgnoredKeys) { ++ var _a; ++ const match = options.ordered ++ ? matchNoteOrdered(note, keysToMatch, options, outIgnoredKeys) ++ : matchNoteUnordered(note, keysToMatch, options, outIgnoredKeys); ++ if (((_a = options.exclusive) !== null && _a !== void 0 ? _a : true) && keysToMatch.length !== note.length) { ++ return false; ++ } ++ return match; ++ } ++ function matchNoteOrdered(note, keysToMatch, options, outIgnoredKeys) { ++ const modifiersFirst = (options === null || options === void 0 ? void 0 : options.ordered) === 'modifiersFirst'; ++ let lastFound = -1; ++ let lastFoundModifier = -1; ++ for (let i = 0; i < note.length; i++) { ++ const code = note[i]; ++ if (code in exports.VIRTUAL_ANY_POSITION_KEYS) { ++ const alternatives = exports.VIRTUAL_ANY_POSITION_KEYS[code]; ++ let anyMatch = false; ++ for (let j = 0; j < alternatives.length; j++) { ++ // we can start at lastFound, anything before that has already been processed ++ const idx = keysToMatch.indexOf(alternatives[j], lastFound + 1); ++ if (idx >= 0 && idx > lastFound) { ++ anyMatch = true; ++ if (modifiersFirst && MODIFIER_KEYS.includes(alternatives[j])) { ++ lastFoundModifier = idx; ++ } ++ else { ++ lastFound = idx; ++ } ++ outIgnoredKeys.push(alternatives[j]); ++ break; ++ } ++ } ++ if (!anyMatch) { ++ return false; ++ } ++ } ++ else { ++ // we can start at lastFound, anything before that has already been processed ++ const idx = keysToMatch.indexOf(note[i], lastFound + 1); ++ if (idx < 0 || idx <= lastFound) { ++ return false; ++ } ++ if (modifiersFirst && MODIFIER_KEYS.includes(note[i])) { ++ lastFoundModifier = idx; ++ } ++ else { ++ lastFound = idx; ++ } ++ outIgnoredKeys.push(note[i]); ++ } ++ // If modifiersFirst, do not allow modifiers after other keys ++ if (modifiersFirst && lastFound >= 0 && lastFoundModifier > lastFound) { ++ return false; ++ } ++ } ++ return true; ++ } ++ function matchNoteUnordered(note, keysToMatch, _options, outIgnoredKeys) { ++ for (let i = 0; i < note.length; i++) { ++ const code = note[i]; ++ if (code in exports.VIRTUAL_ANY_POSITION_KEYS) { ++ const alternatives = exports.VIRTUAL_ANY_POSITION_KEYS[code]; ++ let anyMatch = false; ++ for (let j = 0; j < alternatives.length; j++) { ++ if (keysToMatch.includes(alternatives[j])) { ++ outIgnoredKeys.push(alternatives[j]); ++ anyMatch = true; ++ break; ++ } ++ } ++ if (!anyMatch) { ++ return false; ++ } ++ } ++ else if (!keysToMatch.includes(code)) { ++ return false; ++ } ++ else { ++ outIgnoredKeys.push(code); ++ } ++ } ++ return true; ++ } ++ function isAllowedToExecute(binding, e) { ++ var _a, _b, _c; ++ if (!binding.global && ++ (((_a = document.activeElement) === null || _a === void 0 ? void 0 : _a.tagName) === 'TEXTAREA' || ++ ((_b = document.activeElement) === null || _b === void 0 ? void 0 : _b.tagName) === 'INPUT' || ++ ((_c = document.activeElement) === null || _c === void 0 ? void 0 : _c.shadowRoot))) { ++ return false; ++ } ++ else if (typeof binding.global === 'function') { ++ return !!binding.global(e, stringifyCombo(binding.combo)); ++ } ++ return true; ++ } ++ function callListenerIfAllowed(binding, e, note = 0) { ++ if (!isAllowedToExecute(binding, e) || e[SORENSEN_IMMEDIATE_PROPAGATION_STOPPED]) { ++ return; ++ } ++ binding.listener(Object.assign(e, { ++ comboChordCodes: binding.combo, ++ comboCodes: binding.combo[note], ++ tag: binding.tag, ++ [SORENSEN_IMMEDIATE_PROPAGATION_STOPPED]: false, ++ stopImmediatePropagation: () => { ++ if (e[SORENSEN_IMMEDIATE_PROPAGATION_STOPPED]) { ++ return; ++ } ++ ; ++ e[SORENSEN_IMMEDIATE_PROPAGATION_STOPPED] = true; ++ e[SORENSEN_STOP_IMMEDIATE_PROPAGATION](); ++ }, ++ })); ++ } ++ function insertKeyRepeatIgnoreKeys(binding, e, ignoredKeys) { ++ if (binding.preventDefaultPartials !== false && isAllowedToExecute(binding, e)) { ++ keyRepeatIgnoreKeys = [...keyRepeatIgnoreKeys, ...ignoredKeys]; ++ } ++ } ++ function visitBoundCombos(key, up, e) { ++ const chordsInProgressCount = chordsInProgress.length; ++ bound.forEach((binding) => { ++ var _a; ++ const ignoredKeys = []; ++ if (matchNote(binding.combo[0], up ? [...keysDown, key] : keysDown, binding, ignoredKeys) && ++ ((_a = binding.up) !== null && _a !== void 0 ? _a : false) === up) { ++ if (chordsInProgressCount === 0 || binding.exclusive === false) { ++ if (binding.combo.length === 1) { ++ // DEBUG: console.log(binding, chordsInProgress, binding.exclusive) ++ callListenerIfAllowed(binding, e, 0); ++ } ++ else { ++ // DEBUG: console.log('Begun chord:', binding, binding.exclusive) ++ chordsInProgress.push({ ++ binding, ++ note: 1, ++ }); ++ keyUpIgnoreKeys = [...keyUpIgnoreKeys, ...keysDown]; ++ } ++ } ++ } ++ insertKeyRepeatIgnoreKeys(binding, e, ignoredKeys); ++ }); ++ } ++ function visitChordsInProgress(key, up, e) { ++ const notInProgress = []; ++ // DEBUG: console.log(chordsInProgress) ++ chordsInProgress.forEach((chord) => { ++ var _a; ++ if (((_a = chord.binding.up) !== null && _a !== void 0 ? _a : false) !== up) { ++ // DEBUG: console.log('Wrong direction: ', up) ++ return; ++ } ++ if (chord.binding.combo.length <= chord.note) { ++ // DEBUG: console.log('Too short', chord) ++ notInProgress.push(chord); ++ return; ++ } ++ const ignoredKeys = []; ++ if (matchNote(chord.binding.combo[chord.note], up ? [...keysDown, key] : keysDown, chord.binding, ignoredKeys)) { ++ chord.note = chord.note + 1; ++ // DEBUG: console.log('Did match', chord) ++ if (chord.binding.combo.length === chord.note) { ++ // DEBUG: console.log('Executing', chord) ++ callListenerIfAllowed(chord.binding, e, chord.note); ++ return; // do not set up a new timeout for the chord ++ } ++ keyUpIgnoreKeys = [...keyUpIgnoreKeys, ...keysDown]; ++ } ++ else if (up && keyUpIgnoreKeys.includes(key)) { ++ keyUpIgnoreKeys = keyUpIgnoreKeys.filter((ignoreKey) => ignoreKey !== key); ++ // DEBUG: console.log('Ignored key ticked off', key, keyUpIgnoreKeys) ++ } ++ else if (!noteIncludesKey(chord.binding.combo[chord.note], key) && ++ (chord.binding.modifiersPoisonChord || !MODIFIER_KEYS.includes(key))) { ++ // DEBUG: console.log('No match', chord) ++ notInProgress.push(chord); ++ } ++ insertKeyRepeatIgnoreKeys(chord.binding, e, ignoredKeys); ++ }); ++ chordsInProgress = chordsInProgress.filter((chord) => !notInProgress.includes(chord)); ++ } ++ function registerPreventDefaultDownKeys(_key, e) { ++ const ignoredKeys = []; ++ chordsInProgress.forEach((chord) => { ++ if (!chord.binding.preventDefaultDown) { ++ return; ++ } ++ if (!isAllowedToExecute(chord.binding, e)) { ++ return; ++ } ++ if (chord.note > chord.binding.combo.length) { ++ return; ++ } ++ const ignoredChordKeys = []; ++ const matched = matchNote(chord.binding.combo[chord.note - 1], keysDown, chord.binding, ignoredChordKeys); ++ if (matched) { ++ ; ++ e.defaultPreventedDown = true; ++ ignoredKeys.push(...ignoredChordKeys); ++ } ++ }); ++ bound.forEach((binding) => { ++ if (!binding.preventDefaultDown) { ++ return; ++ } ++ if (!isAllowedToExecute(binding, e)) { ++ return; ++ } ++ if (binding.combo.length !== 1) { ++ return; ++ } ++ const ignoredChordKeys = []; ++ const matched = matchNote(binding.combo[0], keysDown, binding, ignoredChordKeys); ++ if (matched) { ++ ; ++ e.defaultPreventedDown = true; ++ ignoredKeys.push(...ignoredChordKeys); ++ } ++ }); ++ keyRepeatIgnoreKeys = [...keyRepeatIgnoreKeys, ...Array.from(new Set(ignoredKeys))]; ++ } ++ function cleanUpFinishedChords() { ++ chordsInProgress = chordsInProgress.filter((chord) => chord.note < chord.binding.combo.length); ++ } ++ function cleanUpKeyUpIgnoreKeys() { ++ if (keysDown.length === 0) { ++ keyUpIgnoreKeys.length = 0; ++ } ++ } ++ function cleanUpKeyRepeatIgnoreKeys(e) { ++ if (keysDown.length === 0) { ++ keyRepeatIgnoreKeys.length = 0; ++ } ++ if (e) { ++ keyRepeatIgnoreKeys = keyRepeatIgnoreKeys.filter((key) => key !== e.code); ++ } ++ } ++ function preventDefault(e) { ++ e.preventDefault(); ++ } ++ function overloadEventStopImmediatePropagation(e) { ++ return Object.assign(e, { ++ [SORENSEN_STOP_IMMEDIATE_PROPAGATION]: e.stopImmediatePropagation, ++ }); ++ } ++ let chordTimeout = undefined; ++ function setupChordTimeout() { ++ clearChordTimeout(); ++ if (CHORD_TIMEOUT > 0) { ++ chordTimeout = window.setTimeout(() => { ++ chordsInProgress.length = 0; ++ }, CHORD_TIMEOUT); ++ } ++ } ++ function clearChordTimeout() { ++ if (chordTimeout) { ++ clearTimeout(chordTimeout); ++ } ++ chordTimeout = undefined; ++ } ++ /** ++ * Cancel all pressed keys and chords in progress ++ * ++ */ ++ function poison() { ++ chordsInProgress.length = 0; ++ poisoned = true; ++ } ++ function keyUp(e) { ++ keysDown = keysDown.filter((key) => key !== e.code); ++ if (!poisoned) { ++ e = overloadEventStopImmediatePropagation(e); ++ visitChordsInProgress(e.code, true, e); ++ visitBoundCombos(e.code, true, e); ++ } ++ cleanUpFinishedChords(); ++ setupChordTimeout(); ++ cleanUpKeyUpIgnoreKeys(); ++ cleanUpKeyRepeatIgnoreKeys(e); ++ if (poisoned && keysDown.length === 0) { ++ poisoned = false; ++ } ++ // DEBUG: console.log(chordsInProgress) ++ } ++ function keyDown(e) { ++ if (!e.repeat) { ++ keysDown.push(e.code); ++ // DEBUG: console.log(keysDown) ++ if (!poisoned) { ++ e = overloadEventStopImmediatePropagation(e); ++ visitChordsInProgress(e.code, false, e); ++ visitBoundCombos(e.code, false, e); ++ registerPreventDefaultDownKeys(e.code, e); ++ } ++ cleanUpFinishedChords(); ++ clearChordTimeout(); ++ } ++ if (keyRepeatIgnoreKeys.includes(e.code)) { ++ preventDefault(e); ++ } ++ } ++ function visibilityChange() { ++ if ('visibilityState' in document && document.visibilityState === 'hidden') { ++ // reset keysDown when user moved away from the page ++ clearPressedKeys(); ++ } ++ } ++ function windowBlur() { ++ clearPressedKeys(); ++ } ++ async function getKeyboardLayoutMap() { ++ if ('keyboard' in navigator && navigator.keyboard && typeof navigator.keyboard.getLayoutMap === 'function') { ++ try { ++ keyboardLayoutMap = await navigator.keyboard.getLayoutMap(); ++ dispatchEvent('layoutchange'); ++ } ++ catch (e) { ++ console.error('Could not get keyboard layout map.', e); ++ } ++ } ++ } ++ /** ++ * Get the keys currently being pressed ++ * ++ * @return {*} {string[]} A list of key button codes. ++ */ ++ function getPressedKeys() { ++ return [...keysDown]; ++ } ++ function clearPressedKeys() { ++ // inform potential listeners about cancelled keys ++ const cancelledKeys = keysDown.slice(); ++ keysDown.length = 0; ++ cancelledKeys.forEach((code) => dispatchEvent('keycancel', { ++ code, ++ })); ++ poisoned = false; ++ } ++ /** ++ * Figure out the physical key code for a given label. ++ * ++ * @param {string} key The label of a key ++ * @return {*} {(string | undefined)} Key code ++ */ ++ function getCodeForKey(key) { ++ if (key.length === 1) { ++ key = key.toLowerCase(); ++ } ++ if (keyboardLayoutMap) { ++ for (let [code, label] of keyboardLayoutMap.entries()) { ++ if (label === key) { ++ return code; ++ } ++ } ++ } ++ else { ++ if (key.match(/^\d+$/)) { ++ return `Digit${key}`; ++ } ++ else if (key.match(/^\w$/)) { ++ return `Key${key}`; ++ } ++ else { ++ return `${key}`; ++ } ++ } ++ return undefined; ++ } ++ /** ++ * Fetch the key label on the given physical key. ++ * ++ * @param {string} code Key button code ++ * @return {*} {string} Label on the key with the current keyboard layout. ++ */ ++ function getKeyForCode(code) { ++ if (keyboardLayoutMap) { ++ let key = keyboardLayoutMap.get(code); ++ if (key === undefined) { ++ key = code.replace(/^Key/, '').replace(/^Digit(?=\d+)/, ''); ++ if (key.length === 1) { ++ key = key.toLowerCase(); ++ } ++ } ++ return key; ++ } ++ else { ++ // the fallback position is to return the key string without the "Key" prefix, if present. ++ // On US-style keyboards works 9 out of 10 cases. ++ let key = code.replace(/^Key/, '').replace(/^Digit(?=\d+)/, ''); ++ if (key.length === 1) { ++ key = key.toLowerCase(); ++ } ++ return key; ++ } ++ } ++ /** ++ * Initialize Sørensen, get the current keyboard layout map and attach keyboard event listeners to ++ * a root DOM node. ++ * ++ * Default: ++ * * `chordTimeout: 2000` - time in milliseconds waiting for a new keypress in chords ++ * ++ * @param {{ chordTimeout?: number, shadowRoot?: any }} [options] ++ */ ++ async function init(options) { ++ var _a; ++ if (!initialized) { ++ CHORD_TIMEOUT = (_a = options === null || options === void 0 ? void 0 : options.chordTimeout) !== null && _a !== void 0 ? _a : DEFAULT_CHORD_TIMEOUT; ++ window.addEventListener('keyup', keyUp, { ++ passive: false, ++ capture: true, ++ }); ++ window.addEventListener('keydown', keyDown, { ++ passive: false, ++ capture: true, ++ }); ++ window.addEventListener('visibilitychange', visibilityChange); ++ window.addEventListener('blur', windowBlur); ++ window.addEventListener('pagehide', windowBlur); ++ if ('keyboard' in navigator && navigator.keyboard && typeof navigator.keyboard.addEventListener === 'function') { ++ navigator.keyboard.addEventListener('layoutchange', getKeyboardLayoutMap); ++ } ++ await getKeyboardLayoutMap(); ++ bound = []; ++ keysDown = []; ++ chordsInProgress = []; ++ initialized = true; ++ } ++ else { ++ throw new Error('Sørensen already initialized.'); ++ } ++ } ++ /** ++ * Remove all Sørensen event handlers from the window. ++ * ++ */ ++ async function destroy() { ++ if (initialized) { ++ window.removeEventListener('keyup', keyUp); ++ window.removeEventListener('keydown', keyDown); ++ window.removeEventListener('visibilitychange', visibilityChange); ++ window.removeEventListener('blur', windowBlur); ++ window.removeEventListener('pagehide', windowBlur); ++ if ('keyboard' in navigator && navigator.keyboard && typeof navigator.keyboard.removeEventListener === 'function') { ++ navigator.keyboard.removeEventListener('layoutchange', getKeyboardLayoutMap); ++ } ++ initialized = false; ++ } ++ else { ++ throw new Error('Sørensen already destroyed.'); ++ } ++ } ++ const eventListeners = {}; ++ function dispatchEvent(event, args) { ++ if (Array.isArray(eventListeners[event])) { ++ eventListeners[event].forEach((handler) => { ++ try { ++ handler(args); ++ } ++ catch (e) { ++ // simulate the behavior of an exception reaching top-level ++ console.error(e); ++ } ++ }); ++ } ++ } ++ function addEventListener(event, handler) { ++ if (eventListeners[event] === undefined) { ++ eventListeners[event] = []; ++ } ++ eventListeners[event].push(handler); ++ } ++ function removeEventListener(event, handler) { ++ if (Array.isArray(eventListeners[event])) { ++ eventListeners[event] = eventListeners[event].filter((someHandler) => someHandler !== handler); ++ } ++ } ++ exports.Sorensen = { ++ init, ++ destroy, ++ getCodeForKey, ++ getKeyForCode, ++ getPressedKeys, ++ bind, ++ unbind, ++ poison, ++ addEventListener, ++ removeEventListener, ++ }; ++ if (window) { ++ //@ts-ignore this is to work around a bug in webpack DevServer ++ window['sorensen'] = exports.Sorensen; ++ } ++ exports.default = exports.Sorensen; ++}); ++//# sourceMappingURL=index.js.map +\ No newline at end of file +diff --git a/package.json b/package.json +index c6bb696c6a5af164a041b374b1b56f963658a7a3..6755f14f05d4cf5f233309c88c6d93cf41620c1e 100644 +--- a/package.json ++++ b/package.json +@@ -2,10 +2,10 @@ + "name": "@sofie-automation/sorensen", + "version": "1.5.0", + "description": "A modern, i18n-friendly hotkey library for the Web", +- "main": "dist/sorensen.js", ++ "main": "dist/index.js", + "types": "dist/index.d.ts", + "files": [ +- "dist/index.d.ts", ++ "dist", + "README.md", + "CHANGELOG.md" + ], diff --git a/apps/app/package.json b/apps/app/package.json index 57aa0b34..3ab4a295 100644 --- a/apps/app/package.json +++ b/apps/app/package.json @@ -78,7 +78,7 @@ "@shared/models": "^0.12.0-alpha.5", "@shared/server-lib": "^0.12.0-alpha.5", "@shared/tsr-bridge": "^0.12.0-alpha.5", - "@sofie-automation/sorensen": "patch:@sofie-automation/sorensen@npm%3A1.4.3#~/.yarn/patches/@sofie-automation-sorensen-npm-1.4.3-a11a53b994.patch", + "@sofie-automation/sorensen": "patch:@sofie-automation/sorensen@npm%3A1.5.0#~/.yarn/patches/@sofie-automation-sorensen-npm-1.5.0-88bfc56810.patch", "axios": "^1.7.7", "bufferutil": "^4.0.8", "classnames": "^2.5.1", diff --git a/apps/app/src/react/App.tsx b/apps/app/src/react/App.tsx index b3fa3720..4a359da3 100644 --- a/apps/app/src/react/App.tsx +++ b/apps/app/src/react/App.tsx @@ -11,7 +11,7 @@ import '@fontsource/barlow-condensed/500.css' import './styles/app.scss' import { RundownView } from './components/rundown/RundownView.js' import { Sidebar } from './components/sidebar/Sidebar.js' -import { sorensen } from '@sofie-automation/sorensen' +import { Sorensen } from '@sofie-automation/sorensen' import { RealtimeDataProvider } from './api/RealtimeDataProvider.js' import { ApiClient } from './api/ApiClient.js' import { Project, SpecialLedgers } from '../models/project/Project.js' @@ -245,14 +245,14 @@ export const App = observer(function App() { debugKeyPressesLastTime.current = Date.now() } - sorensen.bind('F12', onF12Key, { + Sorensen.bind('F12', onF12Key, { up: false, global: true, exclusive: true, preventDefaultPartials: false, }) return () => { - sorensen.unbind('F12', onF12Key) + Sorensen.unbind('F12', onF12Key) } }, [sorensenInitialized, handleError, serverAPI]) @@ -265,13 +265,13 @@ export const App = observer(function App() { if (document.activeElement?.tagName === 'INPUT') return } - const activeKeys = sorensen.getPressedKeys().map((code) => { + const activeKeys = Sorensen.getPressedKeys().map((code) => { return { fullIdentifier: `keyboard-${code}`, bridgeId: protectString(''), deviceId: PERIPHERAL_KEYBOARD, deviceName: '', - identifier: sorensen.getKeyForCode(code), + identifier: Sorensen.getKeyForCode(code), } }) triggers.setActiveKeys(activeKeys) @@ -321,8 +321,7 @@ export const App = observer(function App() { /* eslint-disable @typescript-eslint/unbound-method */ useEffect(() => { - sorensen - .init() + Sorensen.init() .then(() => { setSorensenInitialized(true) }) @@ -479,7 +478,7 @@ export const App = observer(function App() { } } - sorensen.bind('Delete', onDeleteKey, { + Sorensen.bind('Delete', onDeleteKey, { up: false, global: true, exclusive: true, @@ -487,7 +486,7 @@ export const App = observer(function App() { }) return () => { - sorensen.unbind('Delete', onDeleteKey) + Sorensen.unbind('Delete', onDeleteKey) } }, [sorensenInitialized, handleError, gui, currentRundownId, deleteSelectedTimelineObjs]) @@ -534,24 +533,24 @@ export const App = observer(function App() { setUserAgreementScreenOpen(false) if (undoLedgerKey) serverAPI.redo({ key: undoLedgerKey }).catch(handleError) } - sorensen.bind('Escape', onEscapeKey, { + Sorensen.bind('Escape', onEscapeKey, { up: false, global: true, exclusive: true, preventDefaultPartials: false, }) - sorensen.bind('Control+KeyZ', onUndo, { + Sorensen.bind('Control+KeyZ', onUndo, { up: false, global: true, }) - sorensen.bind('Control+KeyY', onRedo, { + Sorensen.bind('Control+KeyY', onRedo, { up: false, global: true, }) return () => { - sorensen.unbind('Escape', onEscapeKey) - sorensen.unbind('Control+KeyZ', onUndo) - sorensen.unbind('Control+KeyY', onRedo) + Sorensen.unbind('Escape', onEscapeKey) + Sorensen.unbind('Control+KeyZ', onUndo) + Sorensen.unbind('Control+KeyY', onRedo) } }, [sorensenInitialized, handleError, gui, currentRundownId, serverAPI, undoLedgerKey]) diff --git a/apps/app/src/react/components/rundown/GroupView/GroupView.tsx b/apps/app/src/react/components/rundown/GroupView/GroupView.tsx index 2e35b305..0c6f9d3f 100644 --- a/apps/app/src/react/components/rundown/GroupView/GroupView.tsx +++ b/apps/app/src/react/components/rundown/GroupView/GroupView.tsx @@ -1,5 +1,5 @@ import React, { useEffect, useRef, useState, useContext, useCallback } from 'react' -import { sorensen } from '@sofie-automation/sorensen' +import { Sorensen } from '@sofie-automation/sorensen' import { TrashBtn } from '../../inputs/TrashBtn.js' import { GroupBase, GroupGUI } from '../../../../models/rundown/Group.js' import { PartView } from './PartView.js' @@ -146,7 +146,7 @@ export const GroupView: React.FC<{ ) return - const pressed = sorensen.getPressedKeys() + const pressed = Sorensen.getPressedKeys() if (pressed.includes('ControlLeft') || pressed.includes('ControlRight')) { // Add this group to the selection: store.guiStore.toggleAddSelected({ @@ -416,7 +416,7 @@ export const GroupView: React.FC<{ ipcServer.deleteGroup({ rundownId, groupId: group.id }).catch(handleError) }, [group.id, handleError, ipcServer, rundownId]) const handleDeleteClick = useCallback(() => { - const pressedKeys = sorensen.getPressedKeys() + const pressedKeys = Sorensen.getPressedKeys() if (pressedKeys.includes('ControlLeft') || pressedKeys.includes('ControlRight')) { // Delete immediately with no confirmation dialog. handleDelete() @@ -432,7 +432,7 @@ export const GroupView: React.FC<{ // Collapse button: const handleCollapse = useCallback(() => { - const pressed = sorensen.getPressedKeys() + const pressed = Sorensen.getPressedKeys() if (pressed.includes('AltLeft') || pressed.includes('AltRight')) { ipcServer .toggleAllGroupsCollapse({ diff --git a/apps/app/src/react/components/rundown/GroupView/PartView.tsx b/apps/app/src/react/components/rundown/GroupView/PartView.tsx index 6f734b74..4c634279 100644 --- a/apps/app/src/react/components/rundown/GroupView/PartView.tsx +++ b/apps/app/src/react/components/rundown/GroupView/PartView.tsx @@ -1,6 +1,6 @@ import React, { useContext, useLayoutEffect, useMemo, useRef, useState, useEffect, useCallback } from 'react' import { isEmpty } from 'lodash-es' -import { sorensen } from '@sofie-automation/sorensen' +import { Sorensen } from '@sofie-automation/sorensen' import { PlayHead } from './PlayHead.js' import { Layer, LayerEmpty } from './Layer.js' import { @@ -125,7 +125,7 @@ export const PartView: React.FC<{ ) return - const pressed = sorensen.getPressedKeys() + const pressed = Sorensen.getPressedKeys() if (pressed.includes('ControlLeft') || pressed.includes('ControlRight')) { // Add this part to the selection: store.guiStore.toggleAddSelected({ @@ -575,25 +575,25 @@ export const PartView: React.FC<{ useEffect(() => { const onKey = () => { - const pressed = sorensen.getPressedKeys() + const pressed = Sorensen.getPressedKeys() setBypassSnapping(pressed.includes('ShiftLeft') || pressed.includes('ShiftRight')) } onKey() - sorensen.bind('Shift', onKey, { + Sorensen.bind('Shift', onKey, { up: false, global: true, }) - sorensen.bind('Shift', onKey, { + Sorensen.bind('Shift', onKey, { up: true, global: true, }) - sorensen.addEventListener('keycancel', onKey) + Sorensen.addEventListener('keycancel', onKey) return () => { - sorensen.unbind('Shift', onKey) - sorensen.removeEventListener('keycancel', onKey) + Sorensen.unbind('Shift', onKey) + Sorensen.removeEventListener('keycancel', onKey) } }, [hotkeyContext]) @@ -1360,7 +1360,7 @@ const EndCapHover: React.FC<{ disabled={groupOrPartLocked} title={'Delete Part' + (groupOrPartLocked ? ' (disabled due to locked Part or Group)' : '')} onClick={() => { - const pressedKeys = sorensen.getPressedKeys() + const pressedKeys = Sorensen.getPressedKeys() if (pressedKeys.includes('ControlLeft') || pressedKeys.includes('ControlRight')) { // Delete immediately with no confirmation dialog. handleDelete() diff --git a/apps/app/src/react/components/rundown/GroupView/TimelineObject.tsx b/apps/app/src/react/components/rundown/GroupView/TimelineObject.tsx index 4b5e85eb..f033368e 100644 --- a/apps/app/src/react/components/rundown/GroupView/TimelineObject.tsx +++ b/apps/app/src/react/components/rundown/GroupView/TimelineObject.tsx @@ -1,4 +1,4 @@ -import { sorensen } from '@sofie-automation/sorensen' +import { Sorensen } from '@sofie-automation/sorensen' import { describeTimelineObject } from '../../../../lib/TimelineObj.js' import { DeltaPosition, Position, useMovable } from '../../../../lib/useMovable.js' import { TimelineObj } from '../../../../models/rundown/TimelineObj.js' @@ -203,7 +203,7 @@ export const TimelineObject: React.FC<{ useEffect(() => { const onKey = () => { - const pressed = sorensen.getPressedKeys() + const pressed = Sorensen.getPressedKeys() setAllowDuplicate(pressed.includes('AltLeft') || pressed.includes('AltRight')) // Debounce to let setAllowDuplicate update: @@ -214,30 +214,30 @@ export const TimelineObject: React.FC<{ } onKey() - sorensen.bind('Shift', onKey, { + Sorensen.bind('Shift', onKey, { up: false, global: true, }) - sorensen.bind('Shift', onKey, { + Sorensen.bind('Shift', onKey, { up: true, global: true, }) - sorensen.bind('Alt', onKey, { + Sorensen.bind('Alt', onKey, { up: false, global: true, }) - sorensen.bind('Alt', onKey, { + Sorensen.bind('Alt', onKey, { up: true, global: true, }) - sorensen.addEventListener('keycancel', onKey) + Sorensen.addEventListener('keycancel', onKey) return () => { - sorensen.unbind('Shift', onKey) - sorensen.unbind('Alt', onKey) - sorensen.removeEventListener('keycancel', onKey) + Sorensen.unbind('Shift', onKey) + Sorensen.unbind('Alt', onKey) + Sorensen.removeEventListener('keycancel', onKey) } }, [hotkeyContext, move]) @@ -251,7 +251,7 @@ export const TimelineObject: React.FC<{ wasMoving.current = false } - const pressed = sorensen.getPressedKeys() + const pressed = Sorensen.getPressedKeys() if (pressed.includes('ControlLeft') || pressed.includes('ControlRight')) { // Add this timline-object to the selection: store.guiStore.toggleAddSelected({ diff --git a/apps/app/src/react/components/rundown/RundownView.tsx b/apps/app/src/react/components/rundown/RundownView.tsx index c8a0d881..d173c26e 100644 --- a/apps/app/src/react/components/rundown/RundownView.tsx +++ b/apps/app/src/react/components/rundown/RundownView.tsx @@ -1,5 +1,5 @@ import React, { useContext, useEffect, useMemo, useRef, useState } from 'react' -import { sorensen } from '@sofie-automation/sorensen' +import { Sorensen } from '@sofie-automation/sorensen' import { GroupView } from './GroupView/GroupView.js' import { IPCServerContext } from '../../contexts/IPCServer.js' import { useDrop } from 'react-dnd' @@ -148,18 +148,18 @@ export const RundownView: React.FC<{ mappings: Mappings }> = observer(function R } } // Select All - sorensen.bind('Control+KeyA', onKeySelectAll, { + Sorensen.bind('Control+KeyA', onKeySelectAll, { up: false, global: true, }) - sorensen.bind('Command+KeyA', onKeySelectAll, { + Sorensen.bind('Command+KeyA', onKeySelectAll, { up: false, global: true, }) return () => { - sorensen.unbind('Control+KeyA', onKeySelectAll) - sorensen.unbind('Command+KeyA', onKeySelectAll) + Sorensen.unbind('Control+KeyA', onKeySelectAll) + Sorensen.unbind('Command+KeyA', onKeySelectAll) } }, [currentRundownId]) diff --git a/apps/app/src/react/components/sidebar/SidebarResourceLibrary.tsx b/apps/app/src/react/components/sidebar/SidebarResourceLibrary.tsx index 097fb28d..05f66fd8 100644 --- a/apps/app/src/react/components/sidebar/SidebarResourceLibrary.tsx +++ b/apps/app/src/react/components/sidebar/SidebarResourceLibrary.tsx @@ -48,7 +48,7 @@ import { useMemoComputedArray, useMemoComputedObject, useMemoComputedValue } fro import classNames from 'classnames' import { ScrollWatcher } from '../rundown/ScrollWatcher/ScrollWatcher.js' import { computed } from 'mobx' -import { sorensen } from '@sofie-automation/sorensen' +import { Sorensen } from '@sofie-automation/sorensen' import { CB } from '../../lib/errorHandling.js' import { SmallCheckbox } from '../util/SmallCheckbox.js' @@ -245,7 +245,7 @@ export const SidebarResourceLibrary: React.FC = observer(function SidebarResourc const selectedResourceIds = store.guiStore.resourceLibrary.selectedResourceIds let lastSelectedResourceId = store.guiStore.resourceLibrary.lastSelectedResourceId - const pressed = sorensen.getPressedKeys() + const pressed = Sorensen.getPressedKeys() if (pressed.includes('ControlLeft') || pressed.includes('ControlRight')) { // Add this group to the selection, or remove it if it's already there: const foundIndex = selectedResourceIds.indexOf(resource.id) diff --git a/yarn.lock b/yarn.lock index 65023c38..26807f83 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2869,17 +2869,17 @@ __metadata: languageName: node linkType: hard -"@sofie-automation/sorensen@npm:1.4.3": - version: 1.4.3 - resolution: "@sofie-automation/sorensen@npm:1.4.3" - checksum: 10c0/d9b9d739acd009a3ca1b3025d10cca7e152ae244795faf7019e6616ad6f442aff2d8b58ca48487bd9d9d170703458fc46e370523607cd1ce9d73c0af6e428c36 +"@sofie-automation/sorensen@npm:1.5.0": + version: 1.5.0 + resolution: "@sofie-automation/sorensen@npm:1.5.0" + checksum: 10c0/bf4815ae54c1cbbe0faefca94519675a038a19458b3fd4f07d4c28f9729c1bbcc006e51e27a22ec7cc974c3d333ec3d01b2ae775ae2fd77a72cf625a8874d571 languageName: node linkType: hard -"@sofie-automation/sorensen@patch:@sofie-automation/sorensen@npm%3A1.4.3#~/.yarn/patches/@sofie-automation-sorensen-npm-1.4.3-a11a53b994.patch": - version: 1.4.3 - resolution: "@sofie-automation/sorensen@patch:@sofie-automation/sorensen@npm%3A1.4.3#~/.yarn/patches/@sofie-automation-sorensen-npm-1.4.3-a11a53b994.patch::version=1.4.3&hash=41d8d9" - checksum: 10c0/c707b79aad46291a350ef3fc763d40ef9bfc052a72c5b5eefaaef35512e650a7ca740e65183aaa5e53fb8c1300ce3facd209f186acc8d964f7832ef60f48f483 +"@sofie-automation/sorensen@patch:@sofie-automation/sorensen@npm%3A1.5.0#~/.yarn/patches/@sofie-automation-sorensen-npm-1.5.0-88bfc56810.patch": + version: 1.5.0 + resolution: "@sofie-automation/sorensen@patch:@sofie-automation/sorensen@npm%3A1.5.0#~/.yarn/patches/@sofie-automation-sorensen-npm-1.5.0-88bfc56810.patch::version=1.5.0&hash=ae12e3" + checksum: 10c0/bccb0edd166b8ea619692410c91cf1c2ce1d6a64f5bb92be392c81334a1b9478ad6490f15eee9760b88050f0e72a04c12d3df371fea89de207602634e555d01e languageName: node linkType: hard @@ -14535,7 +14535,7 @@ asn1@evs-broadcast/node-asn1: "@shared/models": "npm:^0.12.0-alpha.5" "@shared/server-lib": "npm:^0.12.0-alpha.5" "@shared/tsr-bridge": "npm:^0.12.0-alpha.5" - "@sofie-automation/sorensen": "patch:@sofie-automation/sorensen@npm%3A1.4.3#~/.yarn/patches/@sofie-automation-sorensen-npm-1.4.3-a11a53b994.patch" + "@sofie-automation/sorensen": "patch:@sofie-automation/sorensen@npm%3A1.5.0#~/.yarn/patches/@sofie-automation-sorensen-npm-1.5.0-88bfc56810.patch" "@types/deep-extend": "npm:0.6.2" "@types/jest": "npm:^29.5.13" "@types/koa": "npm:^2.15.0"