keybuddy 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # keybuddy ⌨️
2
2
 
3
+ [![npm version](https://badge.fury.io/js/keybuddy.svg)](https://badge.fury.io/js/keybuddy)
4
+ [![JSR](https://jsr.io/badges/@keybuddy/core)](https://jsr.io/@keybuddy/core)
5
+ [![TypeScript](https://img.shields.io/badge/TypeScript-007ACC?logo=typescript&logoColor=white)](https://www.typescriptlang.org/)
6
+ [![Deno](https://img.shields.io/badge/Deno-000000?logo=deno&logoColor=white)](https://deno.land/)
7
+
3
8
  Define and dispatch shortcuts with easy using keybuddy.
4
9
 
5
10
  **keybuddy** provides a simple and consistent toolset for defining and dispatching keyboard shortcuts in a browser
@@ -13,9 +18,9 @@ yarn add keybuddy
13
18
  ```javascript
14
19
  import key from 'keybuddy';
15
20
 
16
- key('a', e => console.log('a pressed'))
17
- key('shift+r', e => console.log('shift+r pressed'))
18
- key('⌘+shift+r, ctrl+shit+r', e => console.log('ctrl+shit+r pressed'))
21
+ key('a', e => handleKeyPress('a'))
22
+ key('shift+r', e => handleKeyPress('shift+r'))
23
+ key('⌘+shift+r, ctrl+shit+r', e => handleKeyPress('ctrl+shift+r'))
19
24
 
20
25
  ```
21
26
 
@@ -100,7 +105,7 @@ unsafeUnbindKey('option+e', 'myScope')
100
105
  Remove all actions and event listeners
101
106
 
102
107
 
103
- ### creator(doc: HTMLDocument | HTMLElement, filterFn?)
108
+ ### keybuddy(doc: HTMLDocument | HTMLElement, filterFn?)
104
109
 
105
110
  Keybuddy creator can be used to replace key bindings on document
106
111
 
@@ -109,12 +114,21 @@ Keybuddy creator can be used to replace key bindings on document
109
114
  The reasons that events like onpaste, oncopy want fire keyup event for key bindings
110
115
 
111
116
  ```javascript
112
- import creator from 'keybuddy/creator';
117
+ import { createKeybuddy } from 'keybuddy/keybuddy';
113
118
  const iframe = document.getElementById('#iframe').contentWindow;
114
119
  /**
115
120
  * { bind, unbind, unsafeUnbind, unbindScope, setScope, unbindAll, getScope:}
116
121
  */
117
- const myKeybuddy = creator(iframe, filterFn?)
122
+ const myKeybuddy = createKeybuddy(iframe, filterFn?)
118
123
 
119
124
  myKeybuddy.bind('alt+b', action);
120
125
  ```
126
+
127
+ ### Deno
128
+ ```typescript
129
+ import key from "jsr:@keybuddy/core";
130
+
131
+ key('a', e => handleKeyPress('a'))
132
+ key('shift+r', e => handleKeyPress('shift+r'))
133
+ key('⌘+shift+r, ctrl+shit+r', e => handleKeyPress('ctrl+shift+r'))
134
+ ```
package/index.d.mts ADDED
@@ -0,0 +1,21 @@
1
+ declare const DEFAULT_SCOPE = "all";
2
+ declare const KeyStringBrand: unique symbol;
3
+ type KeyString = string & {
4
+ readonly [KeyStringBrand]: true;
5
+ };
6
+
7
+ declare const bind: (keysStr: string, scopeOrMethod: string | ((e: KeyboardEvent) => void), methodOrNull?: (e: KeyboardEvent) => void, { skipOther, }?: {
8
+ skipOther: boolean;
9
+ }) => void;
10
+ declare const getScope: () => string;
11
+ declare const setScope: (scope: string) => void;
12
+ declare const unbindScope: (deleteScope: string) => void;
13
+ declare const unbindAll: () => void;
14
+ declare const destroy: () => void;
15
+ declare const bindKey: (keysStr: string, scopeOrMethod: string | ((e: KeyboardEvent) => void), methodOrNull?: (e: KeyboardEvent) => void, { skipOther, }?: {
16
+ skipOther: boolean;
17
+ }) => void;
18
+ declare const unbindKey: (keysStr: string, scopeOrMethod: string | ((e: KeyboardEvent) => void), methodOrNull?: (e: KeyboardEvent) => void) => void;
19
+ declare const unsafeUnbindKey: (keysStr: string, scope?: string) => void;
20
+
21
+ export { DEFAULT_SCOPE, type KeyString, bindKey, bind as default, destroy, getScope, setScope, unbindAll, unbindKey, unbindScope, unsafeUnbindKey };
package/index.d.ts CHANGED
@@ -1,11 +1,21 @@
1
- import { DEFAULT_SCOPE } from './constants';
2
- declare const bind: (keysStr: string, scopeOrMethod: string | ((e: KeyboardEvent) => void), methodOrNull?: (e: KeyboardEvent) => void, { skipOther }?: {
1
+ declare const DEFAULT_SCOPE = "all";
2
+ declare const KeyStringBrand: unique symbol;
3
+ type KeyString = string & {
4
+ readonly [KeyStringBrand]: true;
5
+ };
6
+
7
+ declare const bind: (keysStr: string, scopeOrMethod: string | ((e: KeyboardEvent) => void), methodOrNull?: (e: KeyboardEvent) => void, { skipOther, }?: {
3
8
  skipOther: boolean;
4
- }) => void, getScope: () => string, setScope: (scope: string) => void, unbindScope: (deleteScope: string) => void, unbindAll: () => void, destroy: () => void;
5
- export declare const bindKey: (keysStr: string, scopeOrMethod: string | ((e: KeyboardEvent) => void), methodOrNull?: (e: KeyboardEvent) => void, { skipOther }?: {
9
+ }) => void;
10
+ declare const getScope: () => string;
11
+ declare const setScope: (scope: string) => void;
12
+ declare const unbindScope: (deleteScope: string) => void;
13
+ declare const unbindAll: () => void;
14
+ declare const destroy: () => void;
15
+ declare const bindKey: (keysStr: string, scopeOrMethod: string | ((e: KeyboardEvent) => void), methodOrNull?: (e: KeyboardEvent) => void, { skipOther, }?: {
6
16
  skipOther: boolean;
7
17
  }) => void;
8
- export declare const unbindKey: (keysStr: string, scopeOrMethod: string | ((e: KeyboardEvent) => void), methodOrNull?: (e: KeyboardEvent) => void) => void;
9
- export declare const unsafeUnbindKey: (keysStr: string, scope?: string | undefined) => void;
10
- export { setScope, unbindScope, unbindAll, getScope, destroy, DEFAULT_SCOPE };
11
- export default bind;
18
+ declare const unbindKey: (keysStr: string, scopeOrMethod: string | ((e: KeyboardEvent) => void), methodOrNull?: (e: KeyboardEvent) => void) => void;
19
+ declare const unsafeUnbindKey: (keysStr: string, scope?: string) => void;
20
+
21
+ export { DEFAULT_SCOPE, type KeyString, bindKey, bind as default, destroy, getScope, setScope, unbindAll, unbindKey, unbindScope, unsafeUnbindKey };
@@ -0,0 +1,3 @@
1
+ /* keybuddy - Modern keyboard shortcuts library */
2
+ "use strict";var keybuddy=(()=>{var E=Object.defineProperty;var q=Object.getOwnPropertyDescriptor;var $=Object.getOwnPropertyNames;var V=Object.prototype.hasOwnProperty;var Y=(e,r)=>{for(var t in r)E(e,t,{get:r[t],enumerable:!0})},j=(e,r,t,s)=>{if(r&&typeof r=="object"||typeof r=="function")for(let c of $(r))!V.call(e,c)&&c!==t&&E(e,c,{get:()=>r[c],enumerable:!(s=q(r,c))||s.enumerable});return e};var J=e=>j(E({},"__esModule",{value:!0}),e);var de={};Y(de,{DEFAULT_SCOPE:()=>u,bindKey:()=>ie,default:()=>ce,destroy:()=>oe,getScope:()=>ee,setScope:()=>te,unbindAll:()=>re,unbindKey:()=>se,unbindScope:()=>ne,unsafeUnbindKey:()=>ae});var u="all",i={SHIFT:1,ALT:2,CTRL:4,META:8},K={"\u21E7":i.SHIFT,shift:i.SHIFT,"\u2325":i.ALT,alt:i.ALT,option:i.ALT,"\u2303":i.CTRL,ctrl:i.CTRL,control:i.CTRL,"\u2318":i.META,cmd:i.META,command:i.META},y={backspace:"Backspace",tab:"Tab",clear:"Clear",enter:"Enter",return:"Enter",esc:"Escape",escape:"Escape",space:" ",left:"ArrowLeft",up:"ArrowUp",right:"ArrowRight",down:"ArrowDown",del:"Delete",delete:"Delete",home:"Home",end:"End",pageup:"PageUp",pagedown:"PageDown",comma:",",".":".","/":"/","`":"`","-":"-","=":"=",";":";","'":"'","[":"[","]":"]","\\":"\\",Meta:"Meta",MetaLeft:"Meta",MetaRight:"Meta",OS:"Meta",ContextMenu:"Meta",ArrowLeft:"ArrowLeft",ArrowUp:"ArrowUp",ArrowRight:"ArrowRight",ArrowDown:"ArrowDown",Backspace:"Backspace",Tab:"Tab",Clear:"Clear",Enter:"Enter",Escape:"Escape",Delete:"Delete",Home:"Home",End:"End",PageUp:"PageUp",PageDown:"PageDown"},x="CapsLock";var S=e=>y[e]||e.toUpperCase(),P=e=>{let r=0;return e.shiftKey&&(r|=i.SHIFT),e.altKey&&(r|=i.ALT),e.ctrlKey&&(r|=i.CTRL),e.metaKey&&(r|=i.META),r};var W=e=>y[e]||e.toUpperCase(),X=e=>e.reduce((r,t)=>(t in K?r.mods|=K[t]:r.special.push(y[t]||t.toUpperCase()),r),{mods:0,special:[]}),z=e=>{let t=e.replace(/\s/g,"").split(",");return t[t.length-1]===""&&(t[t.length-2]+=","),t},h=e=>z(e).map(t=>{let s=t.split("+"),c=s[s.length-1];return{key:W(c),shortcut:X(s)}});var D=navigator.userAgent.includes("Firefox"),U=e=>e.isContentEditable||e.tagName==="INPUT"||e.tagName==="SELECT"||e.tagName==="TEXTAREA",A=(e,r)=>{if(e.length!==r.length)return!1;for(let t=0;t<e.length;t++)if(e[t]!==r[t])return!1;return!0};var G=e=>e&&!U(e.target),v=new WeakMap;function I(e,r=G){let t={},s=new Set,c="all",m=0,H=(o,n,d=()=>{},{skipOther:a}={skipOther:!1})=>{let p=typeof n=="function"?"all":n,l=typeof n=="function"?n:d;h(o).forEach(({key:f,shortcut:g})=>{t[f]||(t[f]=[]),t[f].push({scope:p,method:l,shortcut:g,skipOther:a})})},L=(o,n,d="all")=>{h(o).forEach(({key:a,shortcut:p})=>{let l=t[a];if(Array.isArray(l)){let f=t[a].filter(({scope:g,method:k,shortcut:b})=>!(g===d&&b.mods===p.mods&&A(b.special,p.special)&&(n===null||k===n)));f.length?t[a]=f:delete t[a]}})},O=(o,n,d=()=>{})=>L(o,typeof n=="function"?n:d,typeof n=="function"?"all":n),N=(o,n)=>L(o,null,n),T=o=>{let n=S(o.key);if(!r(o)||D&&n===x||(m=P(o),!(n==="SHIFT"||n==="ALT"||n==="CTRL"||n==="META")&&!s.has(n)&&s.add(n),!(n in t)))return;let a=t[n].filter(({scope:l,shortcut:{special:f,mods:g}})=>l!==c?!1:A(f,Array.from(s))&&g===m),p=a.find(l=>l.skipOther);p?p.method(o):a.forEach(({method:l})=>{l(o)})},w=o=>{let n=S(o.key);o.key&&o.key.toLowerCase()==="meta"?s.clear():s.delete(n)},R=o=>{Object.keys(t).forEach(n=>{let d=n,a=t[d].filter(({scope:p})=>p!==o);a.length?t[d]=a:delete t[d]})},_=o=>{c=o},B=()=>{t={},s.clear()},M=()=>{s.clear()},C=()=>{if(s.clear(),t={},e){let o=v.get(e);o&&(e.removeEventListener("keydown",o.dispatch),e.removeEventListener("keyup",o.cleanUp),window.removeEventListener("focus",o.reset),v.delete(e))}};return C(),v.set(e,{dispatch:T,cleanUp:w,reset:M}),e.addEventListener("keydown",T),e.addEventListener("keyup",w),window.addEventListener("focus",M),{bind:H,unbind:O,unsafeUnbind:N,unbindScope:R,setScope:_,unbindAll:B,getScope:()=>c,destroy:C}}var{bind:F,unbind:Q,unsafeUnbind:Z,getScope:ee,setScope:te,unbindScope:ne,unbindAll:re,destroy:oe}=I(document),ie=F,se=Q,ae=Z;var ce=F;return J(de);})();
3
+ //# sourceMappingURL=index.global.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/constants.ts","../src/helpers/keyboard.ts","../src/helpers/keymap.ts","../src/helpers/utils.ts","../src/keybuddy.ts"],"sourcesContent":["import { DEFAULT_SCOPE } from './constants';\nimport { createKeybuddy } from './keybuddy';\n\nconst {\n bind,\n unbind,\n unsafeUnbind,\n getScope,\n setScope,\n unbindScope,\n unbindAll,\n destroy,\n} = createKeybuddy(document);\n\nexport const bindKey = bind;\nexport const unbindKey = unbind;\nexport const unsafeUnbindKey = unsafeUnbind;\nexport { setScope, unbindScope, unbindAll, getScope, destroy, DEFAULT_SCOPE };\nexport type { KeyString } from './constants';\nexport default bind;\n","\nexport const DEFAULT_SCOPE = 'all';\n\ndeclare const KeyStringBrand: unique symbol;\n\nexport type KeyString = string & { readonly [KeyStringBrand]: true };\n\n// Bitwise flags for modifiers - much faster than object-based tracking\nexport const MODS = {\n SHIFT: 0b0001, // 1\n ALT: 0b0010, // 2\n CTRL: 0b0100, // 4\n META: 0b1000, // 8\n} as const;\n\n// Map string modifier names to bitwise flags for parsing\nexport type ModifierNames = {\n '⇧': number;\n shift: number;\n '⌥': number;\n alt: number;\n option: number;\n '⌃': number;\n ctrl: number;\n control: number;\n '⌘': number;\n cmd: number;\n command: number;\n};\n\nexport const MODIFIERS: ModifierNames = {\n '⇧': MODS.SHIFT,\n shift: MODS.SHIFT,\n '⌥': MODS.ALT,\n alt: MODS.ALT,\n option: MODS.ALT,\n '⌃': MODS.CTRL,\n ctrl: MODS.CTRL,\n control: MODS.CTRL,\n '⌘': MODS.META,\n cmd: MODS.META,\n command: MODS.META,\n};\n\n// Modern key mapping using KeyboardEvent.key values\nexport const SPECIAL: { [key: string]: string } = {\n backspace: 'Backspace',\n tab: 'Tab',\n clear: 'Clear',\n enter: 'Enter',\n return: 'Enter',\n esc: 'Escape',\n escape: 'Escape',\n space: ' ',\n left: 'ArrowLeft',\n up: 'ArrowUp',\n right: 'ArrowRight',\n down: 'ArrowDown',\n del: 'Delete',\n delete: 'Delete',\n home: 'Home',\n end: 'End',\n pageup: 'PageUp',\n pagedown: 'PageDown',\n comma: ',',\n '.': '.',\n '/': '/',\n '`': '`',\n '-': '-',\n '=': '=',\n ';': ';',\n \"'\": \"'\",\n '[': '[',\n ']': ']',\n '\\\\': '\\\\',\n // Normalize Meta key variants\n 'Meta': 'Meta',\n 'MetaLeft': 'Meta',\n 'MetaRight': 'Meta', \n 'OS': 'Meta', // Some browsers use OS instead of Meta\n 'ContextMenu': 'Meta', // Right-click context menu key sometimes acts as Meta\n // Add identity mappings for already-normalized keys\n 'ArrowLeft': 'ArrowLeft',\n 'ArrowUp': 'ArrowUp',\n 'ArrowRight': 'ArrowRight',\n 'ArrowDown': 'ArrowDown',\n 'Backspace': 'Backspace',\n 'Tab': 'Tab',\n 'Clear': 'Clear',\n 'Enter': 'Enter',\n 'Escape': 'Escape',\n 'Delete': 'Delete',\n 'Home': 'Home',\n 'End': 'End',\n 'PageUp': 'PageUp',\n 'PageDown': 'PageDown',\n};\n\nexport const CAPS_LOCK_KEY = 'CapsLock';\n","import { KeyString, MODS, SPECIAL } from '../constants';\n\nexport const getKeyIdentifier = (key: string): KeyString => {\n return (SPECIAL[key] || key.toUpperCase()) as KeyString;\n};\n\nexport const updateModifiers = (e: KeyboardEvent): number => {\n let modifiers = 0;\n if (e.shiftKey) modifiers |= MODS.SHIFT;\n if (e.altKey) modifiers |= MODS.ALT;\n if (e.ctrlKey) modifiers |= MODS.CTRL;\n if (e.metaKey) modifiers |= MODS.META;\n return modifiers;\n};\n","import { KeyString, MODIFIERS, ModifierNames, SPECIAL } from '../constants';\n\nexport interface ParsedShortcut {\n mods: number; // Bitwise flag for modifiers\n special: string[];\n}\nexport interface KeyMap {\n key: KeyString;\n shortcut: ParsedShortcut;\n}\n\nexport const getKeyIdentifier = (key: string): KeyString =>\n (SPECIAL[key] || key.toUpperCase()) as KeyString;\n\nconst getMods = (keys: string[]): ParsedShortcut =>\n keys.reduce(\n (acc, key) => {\n if (key in MODIFIERS) {\n acc.mods |= MODIFIERS[key as keyof ModifierNames];\n } else {\n acc.special.push(SPECIAL[key] || key.toUpperCase());\n }\n return acc;\n },\n {\n mods: 0, // Start with no modifiers\n special: [],\n } as ParsedShortcut,\n );\n\nconst getCombinations = (keysStr: string): string[] => {\n const cleanKeys = keysStr.replace(/\\s/g, '');\n const keys = cleanKeys.split(',');\n if (keys[keys.length - 1] === '') {\n keys[keys.length - 2] += ',';\n }\n\n return keys;\n};\n\nexport const getKeyMap = (keysStr: string): KeyMap[] => {\n const keymap = getCombinations(keysStr);\n return keymap.map((keyCmd) => {\n const keys = keyCmd.split('+');\n const key = keys[keys.length - 1];\n const keyIdentifier = getKeyIdentifier(key);\n\n return {\n key: keyIdentifier,\n shortcut: getMods(keys),\n };\n });\n};\n","export const invariant = (\n condition: boolean,\n message: string,\n ...args: unknown[]\n) => {\n if (\n typeof process !== 'undefined' &&\n process.env &&\n process.env.NODE_ENV === 'development' &&\n !condition\n ) {\n throw new Error(\n `Invariant failed: ${message}${args.length ? ` ${JSON.stringify(args)}` : ''}`,\n );\n }\n};\n\nexport const isFirefox = navigator.userAgent.includes('Firefox');\n\nexport const isEditable = (el: HTMLElement): boolean =>\n el.isContentEditable ||\n el.tagName === 'INPUT' ||\n el.tagName === 'SELECT' ||\n el.tagName === 'TEXTAREA';\n\nexport const isEqArray = (\n arr1: (string | number)[],\n arr2: (string | number)[],\n): boolean => {\n if (arr1.length !== arr2.length) return false;\n\n for (let i = 0; i < arr1.length; i++) {\n if (arr1[i] !== arr2[i]) return false;\n }\n\n return true;\n};\n","import { CAPS_LOCK_KEY, DEFAULT_SCOPE, KeyString } from './constants';\nimport { getKeyIdentifier, updateModifiers } from './helpers/keyboard';\nimport { getKeyMap, ParsedShortcut } from './helpers/keymap';\nimport { invariant, isEditable, isEqArray, isFirefox } from './helpers/utils';\n\ntype noop = (e: KeyboardEvent) => void;\ntype FilterFn = (el: KeyboardEvent) => boolean;\n\ninterface Handler {\n scope: string;\n method: noop;\n shortcut: ParsedShortcut;\n skipOther: boolean;\n}\n\nconst defaultFilter = (e: KeyboardEvent): boolean =>\n e && !isEditable(e.target as HTMLElement);\n\n// WeakMap to track event listener references per document to prevent memory leaks\nconst documentListeners = new WeakMap<\n Document,\n {\n dispatch: (e: KeyboardEvent) => void;\n cleanUp: (e: KeyboardEvent) => void;\n reset: () => void;\n }\n>();\n\nexport function createKeybuddy(\n doc: Document,\n filterFn: FilterFn = defaultFilter,\n) {\n let handlers: { [key: KeyString]: Handler[] } = {};\n const downKeys: Set<KeyString> = new Set();\n let activeScope = DEFAULT_SCOPE;\n\n let modifiers = 0; // Bitwise flag for active modifiers\n\n const bindKey = (\n keysStr: string,\n scopeOrMethod: string | noop,\n methodOrNull: noop = () => {},\n {\n skipOther,\n }: {\n skipOther: boolean;\n } = {\n skipOther: false,\n },\n ): void => {\n const scope: string =\n typeof scopeOrMethod === 'function' ? DEFAULT_SCOPE : scopeOrMethod;\n const method: noop =\n typeof scopeOrMethod === 'function' ? scopeOrMethod : methodOrNull;\n\n getKeyMap(keysStr).forEach(({ key, shortcut }) => {\n if (!handlers[key]) {\n handlers[key] = [];\n }\n const handler = handlers[key];\n if (process.env.NODE_ENV === 'development') {\n if (skipOther) {\n const action = handler.find((i) => i.skipOther);\n invariant(\n !action,\n \"Conflicting 'skipOther' property with action\",\n action,\n );\n }\n }\n\n handler.push({\n scope,\n method,\n shortcut,\n skipOther,\n });\n });\n };\n\n const unbindKeyProcess = (\n keysStr: string,\n deleteMethod: null | noop,\n deleteScope: string = DEFAULT_SCOPE,\n ): void => {\n getKeyMap(keysStr).forEach(({ key, shortcut }) => {\n const handler = handlers[key];\n if (Array.isArray(handler)) {\n const handler = handlers[key].filter(\n ({ scope, method, shortcut: methodShortcut }: Handler) =>\n !(\n scope === deleteScope &&\n methodShortcut.mods === shortcut.mods &&\n isEqArray(methodShortcut.special, shortcut.special) &&\n (deleteMethod === null ? true : method === deleteMethod)\n ),\n );\n if (handler.length) {\n handlers[key] = handler;\n } else {\n delete handlers[key];\n }\n }\n });\n };\n\n const unbindKey = (\n keysStr: string,\n scopeOrMethod: string | noop,\n methodOrNull: noop = () => {},\n ) => {\n const deleteScope: string =\n typeof scopeOrMethod === 'function' ? DEFAULT_SCOPE : scopeOrMethod;\n const deleteMethod: noop =\n typeof scopeOrMethod === 'function' ? scopeOrMethod : methodOrNull;\n return unbindKeyProcess(keysStr, deleteMethod, deleteScope);\n };\n\n const unsafeUnbindKey = (keysStr: string, scope?: string) =>\n unbindKeyProcess(keysStr, null, scope);\n\n const dispatch = (e: KeyboardEvent) => {\n const key = getKeyIdentifier(e.key);\n\n if (!filterFn(e)) {\n return;\n }\n\n // fix firefox behavior when caps lock fires three times onkeydown\n // and don't fire at all onkeyup (Firefox 72)\n if (isFirefox && key === CAPS_LOCK_KEY) {\n return;\n }\n\n modifiers = updateModifiers(e);\n\n // Check if key is not a modifier\n const isModifierKey =\n key === ('SHIFT' as KeyString) ||\n key === ('ALT' as KeyString) ||\n key === ('CTRL' as KeyString) ||\n key === ('META' as KeyString);\n if (!isModifierKey && !downKeys.has(key)) {\n downKeys.add(key);\n }\n // See if we need to ignore the keypress (filter() can can be overridden)\n // by default ignore key presses if a select, textarea, or input is focused\n // if (!assignKey.filter.call(this, event)) return;\n\n // abort if no potentially matching shortcuts found\n if (!(key in handlers)) {\n return;\n }\n\n const currentHandlers = handlers[key].filter(\n ({ scope, shortcut: { special, mods } }) => {\n if (scope !== activeScope) {\n return false;\n }\n\n return isEqArray(special, Array.from(downKeys)) && mods === modifiers;\n },\n );\n\n const primaryAction: Handler | undefined = currentHandlers.find(\n (action) => action.skipOther,\n );\n if (primaryAction) {\n primaryAction.method(e);\n } else {\n currentHandlers.forEach(({ method }) => {\n method(e);\n });\n }\n };\n\n const cleanUp = (e: KeyboardEvent) => {\n const key = getKeyIdentifier(e.key);\n\n // clean all for meta.\n // Main reason is ctrl+z (or any other native command not fires letter keyup on editable inputs)\n if (e.key && e.key.toLowerCase() === 'meta') {\n downKeys.clear();\n } else {\n downKeys.delete(key);\n }\n };\n\n const unbindScope = (deleteScope: string): void => {\n Object.keys(handlers).forEach((key) => {\n const keyString = key as KeyString;\n const handler = handlers[keyString].filter(\n ({ scope }: Handler) => scope !== deleteScope,\n );\n if (handler.length) {\n handlers[keyString] = handler;\n } else {\n delete handlers[keyString];\n }\n });\n };\n\n const setScope = (scope: string): void => {\n activeScope = scope;\n };\n\n const unbindAll = (): void => {\n handlers = {};\n downKeys.clear();\n };\n\n const reset = (): void => {\n downKeys.clear();\n };\n\n const destroy = (): void => {\n downKeys.clear();\n handlers = {};\n if (doc) {\n const listeners = documentListeners.get(doc);\n if (listeners) {\n doc.removeEventListener('keydown', listeners.dispatch);\n doc.removeEventListener('keyup', listeners.cleanUp);\n window.removeEventListener('focus', listeners.reset);\n documentListeners.delete(doc);\n }\n }\n };\n\n // Remove old listeners if they exist\n destroy();\n\n // Store and add new listeners\n documentListeners.set(doc, { dispatch, cleanUp, reset });\n doc.addEventListener('keydown', dispatch);\n doc.addEventListener('keyup', cleanUp);\n window.addEventListener('focus', reset);\n\n return {\n bind: bindKey,\n unbind: unbindKey,\n unsafeUnbind: unsafeUnbindKey,\n unbindScope,\n setScope,\n unbindAll,\n getScope: () => activeScope,\n destroy,\n };\n}\n"],"mappings":"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","names":["src_exports","__export","DEFAULT_SCOPE","bindKey","src_default","destroy","getScope","setScope","unbindAll","unbindKey","unbindScope","unsafeUnbindKey","DEFAULT_SCOPE","MODS","MODIFIERS","SPECIAL","CAPS_LOCK_KEY","getKeyIdentifier","key","SPECIAL","updateModifiers","modifiers","MODS","getKeyIdentifier","key","SPECIAL","getMods","keys","acc","MODIFIERS","getCombinations","keysStr","getKeyMap","keyCmd","isFirefox","isEditable","el","isEqArray","arr1","arr2","i","defaultFilter","isEditable","documentListeners","createKeybuddy","doc","filterFn","handlers","downKeys","activeScope","modifiers","bindKey","keysStr","scopeOrMethod","methodOrNull","skipOther","scope","method","getKeyMap","key","shortcut","unbindKeyProcess","deleteMethod","deleteScope","handler","methodShortcut","isEqArray","unbindKey","unsafeUnbindKey","dispatch","e","getKeyIdentifier","isFirefox","CAPS_LOCK_KEY","updateModifiers","currentHandlers","special","mods","primaryAction","action","cleanUp","unbindScope","keyString","setScope","unbindAll","reset","destroy","listeners","bind","unbind","unsafeUnbind","getScope","setScope","unbindScope","unbindAll","destroy","createKeybuddy","bindKey","unbindKey","unsafeUnbindKey","src_default","bind"]}
package/index.js CHANGED
@@ -1,43 +1,3 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- Object.defineProperty(exports, "DEFAULT_SCOPE", {
7
- enumerable: true,
8
- get: function get() {
9
- return _constants.DEFAULT_SCOPE;
10
- }
11
- });
12
- exports.default = exports.destroy = exports.getScope = exports.unbindAll = exports.unbindScope = exports.setScope = exports.unsafeUnbindKey = exports.unbindKey = exports.bindKey = void 0;
13
-
14
- var _creator = _interopRequireDefault(require("./creator"));
15
-
16
- var _constants = require("./constants");
17
-
18
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
19
-
20
- var {
21
- bind,
22
- unbind,
23
- unsafeUnbind,
24
- getScope,
25
- setScope,
26
- unbindScope,
27
- unbindAll,
28
- destroy
29
- } = (0, _creator.default)(document);
30
- exports.destroy = destroy;
31
- exports.unbindAll = unbindAll;
32
- exports.unbindScope = unbindScope;
33
- exports.setScope = setScope;
34
- exports.getScope = getScope;
35
- var bindKey = bind;
36
- exports.bindKey = bindKey;
37
- var unbindKey = unbind;
38
- exports.unbindKey = unbindKey;
39
- var unsafeUnbindKey = unsafeUnbind;
40
- exports.unsafeUnbindKey = unsafeUnbindKey;
41
- var _default = bind;
42
- exports.default = _default;
43
- //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NyYy9pbmRleC50cyJdLCJuYW1lcyI6WyJiaW5kIiwidW5iaW5kIiwidW5zYWZlVW5iaW5kIiwiZ2V0U2NvcGUiLCJzZXRTY29wZSIsInVuYmluZFNjb3BlIiwidW5iaW5kQWxsIiwiZGVzdHJveSIsImRvY3VtZW50IiwiYmluZEtleSIsInVuYmluZEtleSIsInVuc2FmZVVuYmluZEtleSJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7OztBQUFBOztBQUNBOzs7O0FBRUEsSUFBTTtBQUNKQSxFQUFBQSxJQURJO0FBRUpDLEVBQUFBLE1BRkk7QUFHSkMsRUFBQUEsWUFISTtBQUlKQyxFQUFBQSxRQUpJO0FBS0pDLEVBQUFBLFFBTEk7QUFNSkMsRUFBQUEsV0FOSTtBQU9KQyxFQUFBQSxTQVBJO0FBUUpDLEVBQUFBO0FBUkksSUFTRixzQkFBUUMsUUFBUixDQVRKOzs7Ozs7QUFXTyxJQUFNQyxPQUFPLEdBQUdULElBQWhCOztBQUNBLElBQU1VLFNBQVMsR0FBR1QsTUFBbEI7O0FBQ0EsSUFBTVUsZUFBZSxHQUFHVCxZQUF4Qjs7ZUFFUUYsSSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBjcmVhdG9yIGZyb20gJy4vY3JlYXRvcic7XG5pbXBvcnQgeyBERUZBVUxUX1NDT1BFIH0gZnJvbSAnLi9jb25zdGFudHMnO1xuXG5jb25zdCB7XG4gIGJpbmQsXG4gIHVuYmluZCxcbiAgdW5zYWZlVW5iaW5kLFxuICBnZXRTY29wZSxcbiAgc2V0U2NvcGUsXG4gIHVuYmluZFNjb3BlLFxuICB1bmJpbmRBbGwsXG4gIGRlc3Ryb3lcbn0gPSBjcmVhdG9yKGRvY3VtZW50KTtcblxuZXhwb3J0IGNvbnN0IGJpbmRLZXkgPSBiaW5kO1xuZXhwb3J0IGNvbnN0IHVuYmluZEtleSA9IHVuYmluZDtcbmV4cG9ydCBjb25zdCB1bnNhZmVVbmJpbmRLZXkgPSB1bnNhZmVVbmJpbmQ7XG5leHBvcnQgeyBzZXRTY29wZSwgdW5iaW5kU2NvcGUsIHVuYmluZEFsbCwgZ2V0U2NvcGUsIGRlc3Ryb3ksIERFRkFVTFRfU0NPUEUgfTtcbmV4cG9ydCBkZWZhdWx0IGJpbmQ7XG4iXX0=
1
+ /* keybuddy - Modern keyboard shortcuts library */
2
+ "use strict";var E=Object.defineProperty;var q=Object.getOwnPropertyDescriptor;var $=Object.getOwnPropertyNames;var V=Object.prototype.hasOwnProperty;var Y=(e,r)=>{for(var t in r)E(e,t,{get:r[t],enumerable:!0})},j=(e,r,t,s)=>{if(r&&typeof r=="object"||typeof r=="function")for(let c of $(r))!V.call(e,c)&&c!==t&&E(e,c,{get:()=>r[c],enumerable:!(s=q(r,c))||s.enumerable});return e};var J=e=>j(E({},"__esModule",{value:!0}),e);var de={};Y(de,{DEFAULT_SCOPE:()=>u,bindKey:()=>ie,default:()=>ce,destroy:()=>oe,getScope:()=>ee,setScope:()=>te,unbindAll:()=>re,unbindKey:()=>se,unbindScope:()=>ne,unsafeUnbindKey:()=>ae});module.exports=J(de);var u="all",i={SHIFT:1,ALT:2,CTRL:4,META:8},K={"\u21E7":i.SHIFT,shift:i.SHIFT,"\u2325":i.ALT,alt:i.ALT,option:i.ALT,"\u2303":i.CTRL,ctrl:i.CTRL,control:i.CTRL,"\u2318":i.META,cmd:i.META,command:i.META},y={backspace:"Backspace",tab:"Tab",clear:"Clear",enter:"Enter",return:"Enter",esc:"Escape",escape:"Escape",space:" ",left:"ArrowLeft",up:"ArrowUp",right:"ArrowRight",down:"ArrowDown",del:"Delete",delete:"Delete",home:"Home",end:"End",pageup:"PageUp",pagedown:"PageDown",comma:",",".":".","/":"/","`":"`","-":"-","=":"=",";":";","'":"'","[":"[","]":"]","\\":"\\",Meta:"Meta",MetaLeft:"Meta",MetaRight:"Meta",OS:"Meta",ContextMenu:"Meta",ArrowLeft:"ArrowLeft",ArrowUp:"ArrowUp",ArrowRight:"ArrowRight",ArrowDown:"ArrowDown",Backspace:"Backspace",Tab:"Tab",Clear:"Clear",Enter:"Enter",Escape:"Escape",Delete:"Delete",Home:"Home",End:"End",PageUp:"PageUp",PageDown:"PageDown"},x="CapsLock";var S=e=>y[e]||e.toUpperCase(),P=e=>{let r=0;return e.shiftKey&&(r|=i.SHIFT),e.altKey&&(r|=i.ALT),e.ctrlKey&&(r|=i.CTRL),e.metaKey&&(r|=i.META),r};var W=e=>y[e]||e.toUpperCase(),X=e=>e.reduce((r,t)=>(t in K?r.mods|=K[t]:r.special.push(y[t]||t.toUpperCase()),r),{mods:0,special:[]}),z=e=>{let t=e.replace(/\s/g,"").split(",");return t[t.length-1]===""&&(t[t.length-2]+=","),t},h=e=>z(e).map(t=>{let s=t.split("+"),c=s[s.length-1];return{key:W(c),shortcut:X(s)}});var D=navigator.userAgent.includes("Firefox"),U=e=>e.isContentEditable||e.tagName==="INPUT"||e.tagName==="SELECT"||e.tagName==="TEXTAREA",A=(e,r)=>{if(e.length!==r.length)return!1;for(let t=0;t<e.length;t++)if(e[t]!==r[t])return!1;return!0};var G=e=>e&&!U(e.target),v=new WeakMap;function I(e,r=G){let t={},s=new Set,c="all",m=0,H=(o,n,d=()=>{},{skipOther:a}={skipOther:!1})=>{let p=typeof n=="function"?"all":n,l=typeof n=="function"?n:d;h(o).forEach(({key:f,shortcut:g})=>{t[f]||(t[f]=[]),t[f].push({scope:p,method:l,shortcut:g,skipOther:a})})},L=(o,n,d="all")=>{h(o).forEach(({key:a,shortcut:p})=>{let l=t[a];if(Array.isArray(l)){let f=t[a].filter(({scope:g,method:k,shortcut:b})=>!(g===d&&b.mods===p.mods&&A(b.special,p.special)&&(n===null||k===n)));f.length?t[a]=f:delete t[a]}})},O=(o,n,d=()=>{})=>L(o,typeof n=="function"?n:d,typeof n=="function"?"all":n),N=(o,n)=>L(o,null,n),T=o=>{let n=S(o.key);if(!r(o)||D&&n===x||(m=P(o),!(n==="SHIFT"||n==="ALT"||n==="CTRL"||n==="META")&&!s.has(n)&&s.add(n),!(n in t)))return;let a=t[n].filter(({scope:l,shortcut:{special:f,mods:g}})=>l!==c?!1:A(f,Array.from(s))&&g===m),p=a.find(l=>l.skipOther);p?p.method(o):a.forEach(({method:l})=>{l(o)})},w=o=>{let n=S(o.key);o.key&&o.key.toLowerCase()==="meta"?s.clear():s.delete(n)},R=o=>{Object.keys(t).forEach(n=>{let d=n,a=t[d].filter(({scope:p})=>p!==o);a.length?t[d]=a:delete t[d]})},_=o=>{c=o},B=()=>{t={},s.clear()},M=()=>{s.clear()},C=()=>{if(s.clear(),t={},e){let o=v.get(e);o&&(e.removeEventListener("keydown",o.dispatch),e.removeEventListener("keyup",o.cleanUp),window.removeEventListener("focus",o.reset),v.delete(e))}};return C(),v.set(e,{dispatch:T,cleanUp:w,reset:M}),e.addEventListener("keydown",T),e.addEventListener("keyup",w),window.addEventListener("focus",M),{bind:H,unbind:O,unsafeUnbind:N,unbindScope:R,setScope:_,unbindAll:B,getScope:()=>c,destroy:C}}var{bind:F,unbind:Q,unsafeUnbind:Z,getScope:ee,setScope:te,unbindScope:ne,unbindAll:re,destroy:oe}=I(document),ie=F,se=Q,ae=Z;var ce=F;0&&(module.exports={DEFAULT_SCOPE,bindKey,destroy,getScope,setScope,unbindAll,unbindKey,unbindScope,unsafeUnbindKey});
3
+ //# sourceMappingURL=index.js.map
package/index.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/constants.ts","../src/helpers/keyboard.ts","../src/helpers/keymap.ts","../src/helpers/utils.ts","../src/keybuddy.ts"],"sourcesContent":["import { DEFAULT_SCOPE } from './constants';\nimport { createKeybuddy } from './keybuddy';\n\nconst {\n bind,\n unbind,\n unsafeUnbind,\n getScope,\n setScope,\n unbindScope,\n unbindAll,\n destroy,\n} = createKeybuddy(document);\n\nexport const bindKey = bind;\nexport const unbindKey = unbind;\nexport const unsafeUnbindKey = unsafeUnbind;\nexport { setScope, unbindScope, unbindAll, getScope, destroy, DEFAULT_SCOPE };\nexport type { KeyString } from './constants';\nexport default bind;\n","\nexport const DEFAULT_SCOPE = 'all';\n\ndeclare const KeyStringBrand: unique symbol;\n\nexport type KeyString = string & { readonly [KeyStringBrand]: true };\n\n// Bitwise flags for modifiers - much faster than object-based tracking\nexport const MODS = {\n SHIFT: 0b0001, // 1\n ALT: 0b0010, // 2\n CTRL: 0b0100, // 4\n META: 0b1000, // 8\n} as const;\n\n// Map string modifier names to bitwise flags for parsing\nexport type ModifierNames = {\n '⇧': number;\n shift: number;\n '⌥': number;\n alt: number;\n option: number;\n '⌃': number;\n ctrl: number;\n control: number;\n '⌘': number;\n cmd: number;\n command: number;\n};\n\nexport const MODIFIERS: ModifierNames = {\n '⇧': MODS.SHIFT,\n shift: MODS.SHIFT,\n '⌥': MODS.ALT,\n alt: MODS.ALT,\n option: MODS.ALT,\n '⌃': MODS.CTRL,\n ctrl: MODS.CTRL,\n control: MODS.CTRL,\n '⌘': MODS.META,\n cmd: MODS.META,\n command: MODS.META,\n};\n\n// Modern key mapping using KeyboardEvent.key values\nexport const SPECIAL: { [key: string]: string } = {\n backspace: 'Backspace',\n tab: 'Tab',\n clear: 'Clear',\n enter: 'Enter',\n return: 'Enter',\n esc: 'Escape',\n escape: 'Escape',\n space: ' ',\n left: 'ArrowLeft',\n up: 'ArrowUp',\n right: 'ArrowRight',\n down: 'ArrowDown',\n del: 'Delete',\n delete: 'Delete',\n home: 'Home',\n end: 'End',\n pageup: 'PageUp',\n pagedown: 'PageDown',\n comma: ',',\n '.': '.',\n '/': '/',\n '`': '`',\n '-': '-',\n '=': '=',\n ';': ';',\n \"'\": \"'\",\n '[': '[',\n ']': ']',\n '\\\\': '\\\\',\n // Normalize Meta key variants\n 'Meta': 'Meta',\n 'MetaLeft': 'Meta',\n 'MetaRight': 'Meta', \n 'OS': 'Meta', // Some browsers use OS instead of Meta\n 'ContextMenu': 'Meta', // Right-click context menu key sometimes acts as Meta\n // Add identity mappings for already-normalized keys\n 'ArrowLeft': 'ArrowLeft',\n 'ArrowUp': 'ArrowUp',\n 'ArrowRight': 'ArrowRight',\n 'ArrowDown': 'ArrowDown',\n 'Backspace': 'Backspace',\n 'Tab': 'Tab',\n 'Clear': 'Clear',\n 'Enter': 'Enter',\n 'Escape': 'Escape',\n 'Delete': 'Delete',\n 'Home': 'Home',\n 'End': 'End',\n 'PageUp': 'PageUp',\n 'PageDown': 'PageDown',\n};\n\nexport const CAPS_LOCK_KEY = 'CapsLock';\n","import { KeyString, MODS, SPECIAL } from '../constants';\n\nexport const getKeyIdentifier = (key: string): KeyString => {\n return (SPECIAL[key] || key.toUpperCase()) as KeyString;\n};\n\nexport const updateModifiers = (e: KeyboardEvent): number => {\n let modifiers = 0;\n if (e.shiftKey) modifiers |= MODS.SHIFT;\n if (e.altKey) modifiers |= MODS.ALT;\n if (e.ctrlKey) modifiers |= MODS.CTRL;\n if (e.metaKey) modifiers |= MODS.META;\n return modifiers;\n};\n","import { KeyString, MODIFIERS, ModifierNames, SPECIAL } from '../constants';\n\nexport interface ParsedShortcut {\n mods: number; // Bitwise flag for modifiers\n special: string[];\n}\nexport interface KeyMap {\n key: KeyString;\n shortcut: ParsedShortcut;\n}\n\nexport const getKeyIdentifier = (key: string): KeyString =>\n (SPECIAL[key] || key.toUpperCase()) as KeyString;\n\nconst getMods = (keys: string[]): ParsedShortcut =>\n keys.reduce(\n (acc, key) => {\n if (key in MODIFIERS) {\n acc.mods |= MODIFIERS[key as keyof ModifierNames];\n } else {\n acc.special.push(SPECIAL[key] || key.toUpperCase());\n }\n return acc;\n },\n {\n mods: 0, // Start with no modifiers\n special: [],\n } as ParsedShortcut,\n );\n\nconst getCombinations = (keysStr: string): string[] => {\n const cleanKeys = keysStr.replace(/\\s/g, '');\n const keys = cleanKeys.split(',');\n if (keys[keys.length - 1] === '') {\n keys[keys.length - 2] += ',';\n }\n\n return keys;\n};\n\nexport const getKeyMap = (keysStr: string): KeyMap[] => {\n const keymap = getCombinations(keysStr);\n return keymap.map((keyCmd) => {\n const keys = keyCmd.split('+');\n const key = keys[keys.length - 1];\n const keyIdentifier = getKeyIdentifier(key);\n\n return {\n key: keyIdentifier,\n shortcut: getMods(keys),\n };\n });\n};\n","export const invariant = (\n condition: boolean,\n message: string,\n ...args: unknown[]\n) => {\n if (\n typeof process !== 'undefined' &&\n process.env &&\n process.env.NODE_ENV === 'development' &&\n !condition\n ) {\n throw new Error(\n `Invariant failed: ${message}${args.length ? ` ${JSON.stringify(args)}` : ''}`,\n );\n }\n};\n\nexport const isFirefox = navigator.userAgent.includes('Firefox');\n\nexport const isEditable = (el: HTMLElement): boolean =>\n el.isContentEditable ||\n el.tagName === 'INPUT' ||\n el.tagName === 'SELECT' ||\n el.tagName === 'TEXTAREA';\n\nexport const isEqArray = (\n arr1: (string | number)[],\n arr2: (string | number)[],\n): boolean => {\n if (arr1.length !== arr2.length) return false;\n\n for (let i = 0; i < arr1.length; i++) {\n if (arr1[i] !== arr2[i]) return false;\n }\n\n return true;\n};\n","import { CAPS_LOCK_KEY, DEFAULT_SCOPE, KeyString } from './constants';\nimport { getKeyIdentifier, updateModifiers } from './helpers/keyboard';\nimport { getKeyMap, ParsedShortcut } from './helpers/keymap';\nimport { invariant, isEditable, isEqArray, isFirefox } from './helpers/utils';\n\ntype noop = (e: KeyboardEvent) => void;\ntype FilterFn = (el: KeyboardEvent) => boolean;\n\ninterface Handler {\n scope: string;\n method: noop;\n shortcut: ParsedShortcut;\n skipOther: boolean;\n}\n\nconst defaultFilter = (e: KeyboardEvent): boolean =>\n e && !isEditable(e.target as HTMLElement);\n\n// WeakMap to track event listener references per document to prevent memory leaks\nconst documentListeners = new WeakMap<\n Document,\n {\n dispatch: (e: KeyboardEvent) => void;\n cleanUp: (e: KeyboardEvent) => void;\n reset: () => void;\n }\n>();\n\nexport function createKeybuddy(\n doc: Document,\n filterFn: FilterFn = defaultFilter,\n) {\n let handlers: { [key: KeyString]: Handler[] } = {};\n const downKeys: Set<KeyString> = new Set();\n let activeScope = DEFAULT_SCOPE;\n\n let modifiers = 0; // Bitwise flag for active modifiers\n\n const bindKey = (\n keysStr: string,\n scopeOrMethod: string | noop,\n methodOrNull: noop = () => {},\n {\n skipOther,\n }: {\n skipOther: boolean;\n } = {\n skipOther: false,\n },\n ): void => {\n const scope: string =\n typeof scopeOrMethod === 'function' ? DEFAULT_SCOPE : scopeOrMethod;\n const method: noop =\n typeof scopeOrMethod === 'function' ? scopeOrMethod : methodOrNull;\n\n getKeyMap(keysStr).forEach(({ key, shortcut }) => {\n if (!handlers[key]) {\n handlers[key] = [];\n }\n const handler = handlers[key];\n if (process.env.NODE_ENV === 'development') {\n if (skipOther) {\n const action = handler.find((i) => i.skipOther);\n invariant(\n !action,\n \"Conflicting 'skipOther' property with action\",\n action,\n );\n }\n }\n\n handler.push({\n scope,\n method,\n shortcut,\n skipOther,\n });\n });\n };\n\n const unbindKeyProcess = (\n keysStr: string,\n deleteMethod: null | noop,\n deleteScope: string = DEFAULT_SCOPE,\n ): void => {\n getKeyMap(keysStr).forEach(({ key, shortcut }) => {\n const handler = handlers[key];\n if (Array.isArray(handler)) {\n const handler = handlers[key].filter(\n ({ scope, method, shortcut: methodShortcut }: Handler) =>\n !(\n scope === deleteScope &&\n methodShortcut.mods === shortcut.mods &&\n isEqArray(methodShortcut.special, shortcut.special) &&\n (deleteMethod === null ? true : method === deleteMethod)\n ),\n );\n if (handler.length) {\n handlers[key] = handler;\n } else {\n delete handlers[key];\n }\n }\n });\n };\n\n const unbindKey = (\n keysStr: string,\n scopeOrMethod: string | noop,\n methodOrNull: noop = () => {},\n ) => {\n const deleteScope: string =\n typeof scopeOrMethod === 'function' ? DEFAULT_SCOPE : scopeOrMethod;\n const deleteMethod: noop =\n typeof scopeOrMethod === 'function' ? scopeOrMethod : methodOrNull;\n return unbindKeyProcess(keysStr, deleteMethod, deleteScope);\n };\n\n const unsafeUnbindKey = (keysStr: string, scope?: string) =>\n unbindKeyProcess(keysStr, null, scope);\n\n const dispatch = (e: KeyboardEvent) => {\n const key = getKeyIdentifier(e.key);\n\n if (!filterFn(e)) {\n return;\n }\n\n // fix firefox behavior when caps lock fires three times onkeydown\n // and don't fire at all onkeyup (Firefox 72)\n if (isFirefox && key === CAPS_LOCK_KEY) {\n return;\n }\n\n modifiers = updateModifiers(e);\n\n // Check if key is not a modifier\n const isModifierKey =\n key === ('SHIFT' as KeyString) ||\n key === ('ALT' as KeyString) ||\n key === ('CTRL' as KeyString) ||\n key === ('META' as KeyString);\n if (!isModifierKey && !downKeys.has(key)) {\n downKeys.add(key);\n }\n // See if we need to ignore the keypress (filter() can can be overridden)\n // by default ignore key presses if a select, textarea, or input is focused\n // if (!assignKey.filter.call(this, event)) return;\n\n // abort if no potentially matching shortcuts found\n if (!(key in handlers)) {\n return;\n }\n\n const currentHandlers = handlers[key].filter(\n ({ scope, shortcut: { special, mods } }) => {\n if (scope !== activeScope) {\n return false;\n }\n\n return isEqArray(special, Array.from(downKeys)) && mods === modifiers;\n },\n );\n\n const primaryAction: Handler | undefined = currentHandlers.find(\n (action) => action.skipOther,\n );\n if (primaryAction) {\n primaryAction.method(e);\n } else {\n currentHandlers.forEach(({ method }) => {\n method(e);\n });\n }\n };\n\n const cleanUp = (e: KeyboardEvent) => {\n const key = getKeyIdentifier(e.key);\n\n // clean all for meta.\n // Main reason is ctrl+z (or any other native command not fires letter keyup on editable inputs)\n if (e.key && e.key.toLowerCase() === 'meta') {\n downKeys.clear();\n } else {\n downKeys.delete(key);\n }\n };\n\n const unbindScope = (deleteScope: string): void => {\n Object.keys(handlers).forEach((key) => {\n const keyString = key as KeyString;\n const handler = handlers[keyString].filter(\n ({ scope }: Handler) => scope !== deleteScope,\n );\n if (handler.length) {\n handlers[keyString] = handler;\n } else {\n delete handlers[keyString];\n }\n });\n };\n\n const setScope = (scope: string): void => {\n activeScope = scope;\n };\n\n const unbindAll = (): void => {\n handlers = {};\n downKeys.clear();\n };\n\n const reset = (): void => {\n downKeys.clear();\n };\n\n const destroy = (): void => {\n downKeys.clear();\n handlers = {};\n if (doc) {\n const listeners = documentListeners.get(doc);\n if (listeners) {\n doc.removeEventListener('keydown', listeners.dispatch);\n doc.removeEventListener('keyup', listeners.cleanUp);\n window.removeEventListener('focus', listeners.reset);\n documentListeners.delete(doc);\n }\n }\n };\n\n // Remove old listeners if they exist\n destroy();\n\n // Store and add new listeners\n documentListeners.set(doc, { dispatch, cleanUp, reset });\n doc.addEventListener('keydown', dispatch);\n doc.addEventListener('keyup', cleanUp);\n window.addEventListener('focus', reset);\n\n return {\n bind: bindKey,\n unbind: unbindKey,\n unsafeUnbind: unsafeUnbindKey,\n unbindScope,\n setScope,\n unbindAll,\n getScope: () => activeScope,\n destroy,\n };\n}\n"],"mappings":";yaAAA,IAAAA,GAAA,GAAAC,EAAAD,GAAA,mBAAAE,EAAA,YAAAC,GAAA,YAAAC,GAAA,YAAAC,GAAA,aAAAC,GAAA,aAAAC,GAAA,cAAAC,GAAA,cAAAC,GAAA,gBAAAC,GAAA,oBAAAC,KAAA,eAAAC,EAAAZ,ICCO,IAAMa,EAAgB,MAOhBC,EAAO,CAClB,MAAO,EACP,IAAK,EACL,KAAM,EACN,KAAM,CACR,EAiBaC,EAA2B,CACtC,SAAKD,EAAK,MACV,MAAOA,EAAK,MACZ,SAAKA,EAAK,IACV,IAAKA,EAAK,IACV,OAAQA,EAAK,IACb,SAAKA,EAAK,KACV,KAAMA,EAAK,KACX,QAASA,EAAK,KACd,SAAKA,EAAK,KACV,IAAKA,EAAK,KACV,QAASA,EAAK,IAChB,EAGaE,EAAqC,CAChD,UAAW,YACX,IAAK,MACL,MAAO,QACP,MAAO,QACP,OAAQ,QACR,IAAK,SACL,OAAQ,SACR,MAAO,IACP,KAAM,YACN,GAAI,UACJ,MAAO,aACP,KAAM,YACN,IAAK,SACL,OAAQ,SACR,KAAM,OACN,IAAK,MACL,OAAQ,SACR,SAAU,WACV,MAAO,IACP,IAAK,IACL,IAAK,IACL,IAAK,IACL,IAAK,IACL,IAAK,IACL,IAAK,IACL,IAAK,IACL,IAAK,IACL,IAAK,IACL,KAAM,KAEN,KAAQ,OACR,SAAY,OACZ,UAAa,OACb,GAAM,OACN,YAAe,OAEf,UAAa,YACb,QAAW,UACX,WAAc,aACd,UAAa,YACb,UAAa,YACb,IAAO,MACP,MAAS,QACT,MAAS,QACT,OAAU,SACV,OAAU,SACV,KAAQ,OACR,IAAO,MACP,OAAU,SACV,SAAY,UACd,EAEaC,EAAgB,WChGtB,IAAMC,EAAoBC,GACvBC,EAAQD,CAAG,GAAKA,EAAI,YAAY,EAG7BE,EAAmB,GAA6B,CAC3D,IAAIC,EAAY,EAChB,OAAI,EAAE,WAAUA,GAAaC,EAAK,OAC9B,EAAE,SAAQD,GAAaC,EAAK,KAC5B,EAAE,UAASD,GAAaC,EAAK,MAC7B,EAAE,UAASD,GAAaC,EAAK,MAC1BD,CACT,ECFO,IAAME,EAAoBC,GAC9BC,EAAQD,CAAG,GAAKA,EAAI,YAAY,EAE7BE,EAAWC,GACfA,EAAK,OACH,CAACC,EAAKJ,KACAA,KAAOK,EACTD,EAAI,MAAQC,EAAUL,CAA0B,EAEhDI,EAAI,QAAQ,KAAKH,EAAQD,CAAG,GAAKA,EAAI,YAAY,CAAC,EAE7CI,GAET,CACE,KAAM,EACN,QAAS,CAAC,CACZ,CACF,EAEIE,EAAmBC,GAA8B,CAErD,IAAMJ,EADYI,EAAQ,QAAQ,MAAO,EAAE,EACpB,MAAM,GAAG,EAChC,OAAIJ,EAAKA,EAAK,OAAS,CAAC,IAAM,KAC5BA,EAAKA,EAAK,OAAS,CAAC,GAAK,KAGpBA,CACT,EAEaK,EAAaD,GACTD,EAAgBC,CAAO,EACxB,IAAKE,GAAW,CAC5B,IAAMN,EAAOM,EAAO,MAAM,GAAG,EACvBT,EAAMG,EAAKA,EAAK,OAAS,CAAC,EAGhC,MAAO,CACL,IAHoBJ,EAAiBC,CAAG,EAIxC,SAAUE,EAAQC,CAAI,CACxB,CACF,CAAC,EClCI,IAAMO,EAAY,UAAU,UAAU,SAAS,SAAS,EAElDC,EAAcC,GACzBA,EAAG,mBACHA,EAAG,UAAY,SACfA,EAAG,UAAY,UACfA,EAAG,UAAY,WAEJC,EAAY,CACvBC,EACAC,IACY,CACZ,GAAID,EAAK,SAAWC,EAAK,OAAQ,MAAO,GAExC,QAASC,EAAI,EAAGA,EAAIF,EAAK,OAAQE,IAC/B,GAAIF,EAAKE,CAAC,IAAMD,EAAKC,CAAC,EAAG,MAAO,GAGlC,MAAO,EACT,ECrBA,IAAMC,EAAiB,GACrB,GAAK,CAACC,EAAW,EAAE,MAAqB,EAGpCC,EAAoB,IAAI,QASvB,SAASC,EACdC,EACAC,EAAqBL,EACrB,CACA,IAAIM,EAA4C,CAAC,EAC3CC,EAA2B,IAAI,IACjCC,EAAc,MAEdC,EAAY,EAEVC,EAAU,CACdC,EACAC,EACAC,EAAqB,IAAM,CAAC,EAC5B,CACE,UAAAC,CACF,EAEI,CACF,UAAW,EACb,IACS,CACT,IAAMC,EACJ,OAAOH,GAAkB,WAAa,MAAgBA,EAClDI,EACJ,OAAOJ,GAAkB,WAAaA,EAAgBC,EAExDI,EAAUN,CAAO,EAAE,QAAQ,CAAC,CAAE,IAAAO,EAAK,SAAAC,CAAS,IAAM,CAC3Cb,EAASY,CAAG,IACfZ,EAASY,CAAG,EAAI,CAAC,GAEHZ,EAASY,CAAG,EAYpB,KAAK,CACX,MAAAH,EACA,OAAAC,EACA,SAAAG,EACA,UAAAL,CACF,CAAC,CACH,CAAC,CACH,EAEMM,EAAmB,CACvBT,EACAU,EACAC,EAAsB,QACb,CACTL,EAAUN,CAAO,EAAE,QAAQ,CAAC,CAAE,IAAAO,EAAK,SAAAC,CAAS,IAAM,CAChD,IAAMI,EAAUjB,EAASY,CAAG,EAC5B,GAAI,MAAM,QAAQK,CAAO,EAAG,CAC1B,IAAMA,EAAUjB,EAASY,CAAG,EAAE,OAC5B,CAAC,CAAE,MAAAH,EAAO,OAAAC,EAAQ,SAAUQ,CAAe,IACzC,EACET,IAAUO,GACVE,EAAe,OAASL,EAAS,MACjCM,EAAUD,EAAe,QAASL,EAAS,OAAO,IACjDE,IAAiB,MAAcL,IAAWK,GAEjD,EACIE,EAAQ,OACVjB,EAASY,CAAG,EAAIK,EAEhB,OAAOjB,EAASY,CAAG,CAEvB,CACF,CAAC,CACH,EAEMQ,EAAY,CAChBf,EACAC,EACAC,EAAqB,IAAM,CAAC,IAMrBO,EAAiBT,EADtB,OAAOC,GAAkB,WAAaA,EAAgBC,EAFtD,OAAOD,GAAkB,WAAa,MAAgBA,CAGE,EAGtDe,EAAkB,CAAChB,EAAiBI,IACxCK,EAAiBT,EAAS,KAAMI,CAAK,EAEjCa,EAAYC,GAAqB,CACrC,IAAMX,EAAMY,EAAiBD,EAAE,GAAG,EA4BlC,GA1BI,CAACxB,EAASwB,CAAC,GAMXE,GAAab,IAAQc,IAIzBvB,EAAYwB,EAAgBJ,CAAC,EAQzB,EAJFX,IAAS,SACTA,IAAS,OACTA,IAAS,QACTA,IAAS,SACW,CAACX,EAAS,IAAIW,CAAG,GACrCX,EAAS,IAAIW,CAAG,EAOd,EAAEA,KAAOZ,IACX,OAGF,IAAM4B,EAAkB5B,EAASY,CAAG,EAAE,OACpC,CAAC,CAAE,MAAAH,EAAO,SAAU,CAAE,QAAAoB,EAAS,KAAAC,CAAK,CAAE,IAChCrB,IAAUP,EACL,GAGFiB,EAAUU,EAAS,MAAM,KAAK5B,CAAQ,CAAC,GAAK6B,IAAS3B,CAEhE,EAEM4B,EAAqCH,EAAgB,KACxDI,GAAWA,EAAO,SACrB,EACID,EACFA,EAAc,OAAOR,CAAC,EAEtBK,EAAgB,QAAQ,CAAC,CAAE,OAAAlB,CAAO,IAAM,CACtCA,EAAOa,CAAC,CACV,CAAC,CAEL,EAEMU,EAAWV,GAAqB,CACpC,IAAMX,EAAMY,EAAiBD,EAAE,GAAG,EAI9BA,EAAE,KAAOA,EAAE,IAAI,YAAY,IAAM,OACnCtB,EAAS,MAAM,EAEfA,EAAS,OAAOW,CAAG,CAEvB,EAEMsB,EAAelB,GAA8B,CACjD,OAAO,KAAKhB,CAAQ,EAAE,QAASY,GAAQ,CACrC,IAAMuB,EAAYvB,EACZK,EAAUjB,EAASmC,CAAS,EAAE,OAClC,CAAC,CAAE,MAAA1B,CAAM,IAAeA,IAAUO,CACpC,EACIC,EAAQ,OACVjB,EAASmC,CAAS,EAAIlB,EAEtB,OAAOjB,EAASmC,CAAS,CAE7B,CAAC,CACH,EAEMC,EAAY3B,GAAwB,CACxCP,EAAcO,CAChB,EAEM4B,EAAY,IAAY,CAC5BrC,EAAW,CAAC,EACZC,EAAS,MAAM,CACjB,EAEMqC,EAAQ,IAAY,CACxBrC,EAAS,MAAM,CACjB,EAEMsC,EAAU,IAAY,CAG1B,GAFAtC,EAAS,MAAM,EACfD,EAAW,CAAC,EACRF,EAAK,CACP,IAAM0C,EAAY5C,EAAkB,IAAIE,CAAG,EACvC0C,IACF1C,EAAI,oBAAoB,UAAW0C,EAAU,QAAQ,EACrD1C,EAAI,oBAAoB,QAAS0C,EAAU,OAAO,EAClD,OAAO,oBAAoB,QAASA,EAAU,KAAK,EACnD5C,EAAkB,OAAOE,CAAG,EAEhC,CACF,EAGA,OAAAyC,EAAQ,EAGR3C,EAAkB,IAAIE,EAAK,CAAE,SAAAwB,EAAU,QAAAW,EAAS,MAAAK,CAAM,CAAC,EACvDxC,EAAI,iBAAiB,UAAWwB,CAAQ,EACxCxB,EAAI,iBAAiB,QAASmC,CAAO,EACrC,OAAO,iBAAiB,QAASK,CAAK,EAE/B,CACL,KAAMlC,EACN,OAAQgB,EACR,aAAcC,EACd,YAAAa,EACA,SAAAE,EACA,UAAAC,EACA,SAAU,IAAMnC,EAChB,QAAAqC,CACF,CACF,CLrPA,GAAM,CACJ,KAAAE,EACA,OAAAC,EACA,aAAAC,EACA,SAAAC,GACA,SAAAC,GACA,YAAAC,GACA,UAAAC,GACA,QAAAC,EACF,EAAIC,EAAe,QAAQ,EAEdC,GAAUT,EACVU,GAAYT,EACZU,GAAkBT,EAG/B,IAAOU,GAAQC","names":["src_exports","__export","DEFAULT_SCOPE","bindKey","src_default","destroy","getScope","setScope","unbindAll","unbindKey","unbindScope","unsafeUnbindKey","__toCommonJS","DEFAULT_SCOPE","MODS","MODIFIERS","SPECIAL","CAPS_LOCK_KEY","getKeyIdentifier","key","SPECIAL","updateModifiers","modifiers","MODS","getKeyIdentifier","key","SPECIAL","getMods","keys","acc","MODIFIERS","getCombinations","keysStr","getKeyMap","keyCmd","isFirefox","isEditable","el","isEqArray","arr1","arr2","i","defaultFilter","isEditable","documentListeners","createKeybuddy","doc","filterFn","handlers","downKeys","activeScope","modifiers","bindKey","keysStr","scopeOrMethod","methodOrNull","skipOther","scope","method","getKeyMap","key","shortcut","unbindKeyProcess","deleteMethod","deleteScope","handler","methodShortcut","isEqArray","unbindKey","unsafeUnbindKey","dispatch","e","getKeyIdentifier","isFirefox","CAPS_LOCK_KEY","updateModifiers","currentHandlers","special","mods","primaryAction","action","cleanUp","unbindScope","keyString","setScope","unbindAll","reset","destroy","listeners","bind","unbind","unsafeUnbind","getScope","setScope","unbindScope","unbindAll","destroy","createKeybuddy","bindKey","unbindKey","unsafeUnbindKey","src_default","bind"]}
package/index.mjs ADDED
@@ -0,0 +1,3 @@
1
+ /* keybuddy - Modern keyboard shortcuts library */
2
+ var f="all",i={SHIFT:1,ALT:2,CTRL:4,META:8},E={"\u21E7":i.SHIFT,shift:i.SHIFT,"\u2325":i.ALT,alt:i.ALT,option:i.ALT,"\u2303":i.CTRL,ctrl:i.CTRL,control:i.CTRL,"\u2318":i.META,cmd:i.META,command:i.META},y={backspace:"Backspace",tab:"Tab",clear:"Clear",enter:"Enter",return:"Enter",esc:"Escape",escape:"Escape",space:" ",left:"ArrowLeft",up:"ArrowUp",right:"ArrowRight",down:"ArrowDown",del:"Delete",delete:"Delete",home:"Home",end:"End",pageup:"PageUp",pagedown:"PageDown",comma:",",".":".","/":"/","`":"`","-":"-","=":"=",";":";","'":"'","[":"[","]":"]","\\":"\\",Meta:"Meta",MetaLeft:"Meta",MetaRight:"Meta",OS:"Meta",ContextMenu:"Meta",ArrowLeft:"ArrowLeft",ArrowUp:"ArrowUp",ArrowRight:"ArrowRight",ArrowDown:"ArrowDown",Backspace:"Backspace",Tab:"Tab",Clear:"Clear",Enter:"Enter",Escape:"Escape",Delete:"Delete",Home:"Home",End:"End",PageUp:"PageUp",PageDown:"PageDown"},k="CapsLock";var K=e=>y[e]||e.toUpperCase(),x=e=>{let o=0;return e.shiftKey&&(o|=i.SHIFT),e.altKey&&(o|=i.ALT),e.ctrlKey&&(o|=i.CTRL),e.metaKey&&(o|=i.META),o};var B=e=>y[e]||e.toUpperCase(),q=e=>e.reduce((o,t)=>(t in E?o.mods|=E[t]:o.special.push(y[t]||t.toUpperCase()),o),{mods:0,special:[]}),$=e=>{let t=e.replace(/\s/g,"").split(",");return t[t.length-1]===""&&(t[t.length-2]+=","),t},S=e=>$(e).map(t=>{let a=t.split("+"),u=a[a.length-1];return{key:B(u),shortcut:q(a)}});var P=navigator.userAgent.includes("Firefox"),D=e=>e.isContentEditable||e.tagName==="INPUT"||e.tagName==="SELECT"||e.tagName==="TEXTAREA",h=(e,o)=>{if(e.length!==o.length)return!1;for(let t=0;t<e.length;t++)if(e[t]!==o[t])return!1;return!0};var V=e=>e&&!D(e.target),A=new WeakMap;function U(e,o=V){let t={},a=new Set,u="all",m=0,F=(r,n,c=()=>{},{skipOther:s}={skipOther:!1})=>{let d=typeof n=="function"?"all":n,p=typeof n=="function"?n:c;S(r).forEach(({key:l,shortcut:g})=>{t[l]||(t[l]=[]),t[l].push({scope:d,method:p,shortcut:g,skipOther:s})})},v=(r,n,c="all")=>{S(r).forEach(({key:s,shortcut:d})=>{let p=t[s];if(Array.isArray(p)){let l=t[s].filter(({scope:g,method:C,shortcut:b})=>!(g===c&&b.mods===d.mods&&h(b.special,d.special)&&(n===null||C===n)));l.length?t[s]=l:delete t[s]}})},H=(r,n,c=()=>{})=>v(r,typeof n=="function"?n:c,typeof n=="function"?"all":n),O=(r,n)=>v(r,null,n),L=r=>{let n=K(r.key);if(!o(r)||P&&n===k||(m=x(r),!(n==="SHIFT"||n==="ALT"||n==="CTRL"||n==="META")&&!a.has(n)&&a.add(n),!(n in t)))return;let s=t[n].filter(({scope:p,shortcut:{special:l,mods:g}})=>p!==u?!1:h(l,Array.from(a))&&g===m),d=s.find(p=>p.skipOther);d?d.method(r):s.forEach(({method:p})=>{p(r)})},T=r=>{let n=K(r.key);r.key&&r.key.toLowerCase()==="meta"?a.clear():a.delete(n)},N=r=>{Object.keys(t).forEach(n=>{let c=n,s=t[c].filter(({scope:d})=>d!==r);s.length?t[c]=s:delete t[c]})},R=r=>{u=r},_=()=>{t={},a.clear()},w=()=>{a.clear()},M=()=>{if(a.clear(),t={},e){let r=A.get(e);r&&(e.removeEventListener("keydown",r.dispatch),e.removeEventListener("keyup",r.cleanUp),window.removeEventListener("focus",r.reset),A.delete(e))}};return M(),A.set(e,{dispatch:L,cleanUp:T,reset:w}),e.addEventListener("keydown",L),e.addEventListener("keyup",T),window.addEventListener("focus",w),{bind:F,unbind:H,unsafeUnbind:O,unbindScope:N,setScope:R,unbindAll:_,getScope:()=>u,destroy:M}}var{bind:I,unbind:Y,unsafeUnbind:j,getScope:ue,setScope:ge,unbindScope:ye,unbindAll:me,destroy:be}=U(document),Ee=I,Ke=Y,Se=j;var he=I;export{f as DEFAULT_SCOPE,Ee as bindKey,he as default,be as destroy,ue as getScope,ge as setScope,me as unbindAll,Ke as unbindKey,ye as unbindScope,Se as unsafeUnbindKey};
3
+ //# sourceMappingURL=index.mjs.map
package/index.mjs.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/constants.ts","../src/helpers/keyboard.ts","../src/helpers/keymap.ts","../src/helpers/utils.ts","../src/keybuddy.ts","../src/index.ts"],"sourcesContent":["\nexport const DEFAULT_SCOPE = 'all';\n\ndeclare const KeyStringBrand: unique symbol;\n\nexport type KeyString = string & { readonly [KeyStringBrand]: true };\n\n// Bitwise flags for modifiers - much faster than object-based tracking\nexport const MODS = {\n SHIFT: 0b0001, // 1\n ALT: 0b0010, // 2\n CTRL: 0b0100, // 4\n META: 0b1000, // 8\n} as const;\n\n// Map string modifier names to bitwise flags for parsing\nexport type ModifierNames = {\n '⇧': number;\n shift: number;\n '⌥': number;\n alt: number;\n option: number;\n '⌃': number;\n ctrl: number;\n control: number;\n '⌘': number;\n cmd: number;\n command: number;\n};\n\nexport const MODIFIERS: ModifierNames = {\n '⇧': MODS.SHIFT,\n shift: MODS.SHIFT,\n '⌥': MODS.ALT,\n alt: MODS.ALT,\n option: MODS.ALT,\n '⌃': MODS.CTRL,\n ctrl: MODS.CTRL,\n control: MODS.CTRL,\n '⌘': MODS.META,\n cmd: MODS.META,\n command: MODS.META,\n};\n\n// Modern key mapping using KeyboardEvent.key values\nexport const SPECIAL: { [key: string]: string } = {\n backspace: 'Backspace',\n tab: 'Tab',\n clear: 'Clear',\n enter: 'Enter',\n return: 'Enter',\n esc: 'Escape',\n escape: 'Escape',\n space: ' ',\n left: 'ArrowLeft',\n up: 'ArrowUp',\n right: 'ArrowRight',\n down: 'ArrowDown',\n del: 'Delete',\n delete: 'Delete',\n home: 'Home',\n end: 'End',\n pageup: 'PageUp',\n pagedown: 'PageDown',\n comma: ',',\n '.': '.',\n '/': '/',\n '`': '`',\n '-': '-',\n '=': '=',\n ';': ';',\n \"'\": \"'\",\n '[': '[',\n ']': ']',\n '\\\\': '\\\\',\n // Normalize Meta key variants\n 'Meta': 'Meta',\n 'MetaLeft': 'Meta',\n 'MetaRight': 'Meta', \n 'OS': 'Meta', // Some browsers use OS instead of Meta\n 'ContextMenu': 'Meta', // Right-click context menu key sometimes acts as Meta\n // Add identity mappings for already-normalized keys\n 'ArrowLeft': 'ArrowLeft',\n 'ArrowUp': 'ArrowUp',\n 'ArrowRight': 'ArrowRight',\n 'ArrowDown': 'ArrowDown',\n 'Backspace': 'Backspace',\n 'Tab': 'Tab',\n 'Clear': 'Clear',\n 'Enter': 'Enter',\n 'Escape': 'Escape',\n 'Delete': 'Delete',\n 'Home': 'Home',\n 'End': 'End',\n 'PageUp': 'PageUp',\n 'PageDown': 'PageDown',\n};\n\nexport const CAPS_LOCK_KEY = 'CapsLock';\n","import { KeyString, MODS, SPECIAL } from '../constants';\n\nexport const getKeyIdentifier = (key: string): KeyString => {\n return (SPECIAL[key] || key.toUpperCase()) as KeyString;\n};\n\nexport const updateModifiers = (e: KeyboardEvent): number => {\n let modifiers = 0;\n if (e.shiftKey) modifiers |= MODS.SHIFT;\n if (e.altKey) modifiers |= MODS.ALT;\n if (e.ctrlKey) modifiers |= MODS.CTRL;\n if (e.metaKey) modifiers |= MODS.META;\n return modifiers;\n};\n","import { KeyString, MODIFIERS, ModifierNames, SPECIAL } from '../constants';\n\nexport interface ParsedShortcut {\n mods: number; // Bitwise flag for modifiers\n special: string[];\n}\nexport interface KeyMap {\n key: KeyString;\n shortcut: ParsedShortcut;\n}\n\nexport const getKeyIdentifier = (key: string): KeyString =>\n (SPECIAL[key] || key.toUpperCase()) as KeyString;\n\nconst getMods = (keys: string[]): ParsedShortcut =>\n keys.reduce(\n (acc, key) => {\n if (key in MODIFIERS) {\n acc.mods |= MODIFIERS[key as keyof ModifierNames];\n } else {\n acc.special.push(SPECIAL[key] || key.toUpperCase());\n }\n return acc;\n },\n {\n mods: 0, // Start with no modifiers\n special: [],\n } as ParsedShortcut,\n );\n\nconst getCombinations = (keysStr: string): string[] => {\n const cleanKeys = keysStr.replace(/\\s/g, '');\n const keys = cleanKeys.split(',');\n if (keys[keys.length - 1] === '') {\n keys[keys.length - 2] += ',';\n }\n\n return keys;\n};\n\nexport const getKeyMap = (keysStr: string): KeyMap[] => {\n const keymap = getCombinations(keysStr);\n return keymap.map((keyCmd) => {\n const keys = keyCmd.split('+');\n const key = keys[keys.length - 1];\n const keyIdentifier = getKeyIdentifier(key);\n\n return {\n key: keyIdentifier,\n shortcut: getMods(keys),\n };\n });\n};\n","export const invariant = (\n condition: boolean,\n message: string,\n ...args: unknown[]\n) => {\n if (\n typeof process !== 'undefined' &&\n process.env &&\n process.env.NODE_ENV === 'development' &&\n !condition\n ) {\n throw new Error(\n `Invariant failed: ${message}${args.length ? ` ${JSON.stringify(args)}` : ''}`,\n );\n }\n};\n\nexport const isFirefox = navigator.userAgent.includes('Firefox');\n\nexport const isEditable = (el: HTMLElement): boolean =>\n el.isContentEditable ||\n el.tagName === 'INPUT' ||\n el.tagName === 'SELECT' ||\n el.tagName === 'TEXTAREA';\n\nexport const isEqArray = (\n arr1: (string | number)[],\n arr2: (string | number)[],\n): boolean => {\n if (arr1.length !== arr2.length) return false;\n\n for (let i = 0; i < arr1.length; i++) {\n if (arr1[i] !== arr2[i]) return false;\n }\n\n return true;\n};\n","import { CAPS_LOCK_KEY, DEFAULT_SCOPE, KeyString } from './constants';\nimport { getKeyIdentifier, updateModifiers } from './helpers/keyboard';\nimport { getKeyMap, ParsedShortcut } from './helpers/keymap';\nimport { invariant, isEditable, isEqArray, isFirefox } from './helpers/utils';\n\ntype noop = (e: KeyboardEvent) => void;\ntype FilterFn = (el: KeyboardEvent) => boolean;\n\ninterface Handler {\n scope: string;\n method: noop;\n shortcut: ParsedShortcut;\n skipOther: boolean;\n}\n\nconst defaultFilter = (e: KeyboardEvent): boolean =>\n e && !isEditable(e.target as HTMLElement);\n\n// WeakMap to track event listener references per document to prevent memory leaks\nconst documentListeners = new WeakMap<\n Document,\n {\n dispatch: (e: KeyboardEvent) => void;\n cleanUp: (e: KeyboardEvent) => void;\n reset: () => void;\n }\n>();\n\nexport function createKeybuddy(\n doc: Document,\n filterFn: FilterFn = defaultFilter,\n) {\n let handlers: { [key: KeyString]: Handler[] } = {};\n const downKeys: Set<KeyString> = new Set();\n let activeScope = DEFAULT_SCOPE;\n\n let modifiers = 0; // Bitwise flag for active modifiers\n\n const bindKey = (\n keysStr: string,\n scopeOrMethod: string | noop,\n methodOrNull: noop = () => {},\n {\n skipOther,\n }: {\n skipOther: boolean;\n } = {\n skipOther: false,\n },\n ): void => {\n const scope: string =\n typeof scopeOrMethod === 'function' ? DEFAULT_SCOPE : scopeOrMethod;\n const method: noop =\n typeof scopeOrMethod === 'function' ? scopeOrMethod : methodOrNull;\n\n getKeyMap(keysStr).forEach(({ key, shortcut }) => {\n if (!handlers[key]) {\n handlers[key] = [];\n }\n const handler = handlers[key];\n if (process.env.NODE_ENV === 'development') {\n if (skipOther) {\n const action = handler.find((i) => i.skipOther);\n invariant(\n !action,\n \"Conflicting 'skipOther' property with action\",\n action,\n );\n }\n }\n\n handler.push({\n scope,\n method,\n shortcut,\n skipOther,\n });\n });\n };\n\n const unbindKeyProcess = (\n keysStr: string,\n deleteMethod: null | noop,\n deleteScope: string = DEFAULT_SCOPE,\n ): void => {\n getKeyMap(keysStr).forEach(({ key, shortcut }) => {\n const handler = handlers[key];\n if (Array.isArray(handler)) {\n const handler = handlers[key].filter(\n ({ scope, method, shortcut: methodShortcut }: Handler) =>\n !(\n scope === deleteScope &&\n methodShortcut.mods === shortcut.mods &&\n isEqArray(methodShortcut.special, shortcut.special) &&\n (deleteMethod === null ? true : method === deleteMethod)\n ),\n );\n if (handler.length) {\n handlers[key] = handler;\n } else {\n delete handlers[key];\n }\n }\n });\n };\n\n const unbindKey = (\n keysStr: string,\n scopeOrMethod: string | noop,\n methodOrNull: noop = () => {},\n ) => {\n const deleteScope: string =\n typeof scopeOrMethod === 'function' ? DEFAULT_SCOPE : scopeOrMethod;\n const deleteMethod: noop =\n typeof scopeOrMethod === 'function' ? scopeOrMethod : methodOrNull;\n return unbindKeyProcess(keysStr, deleteMethod, deleteScope);\n };\n\n const unsafeUnbindKey = (keysStr: string, scope?: string) =>\n unbindKeyProcess(keysStr, null, scope);\n\n const dispatch = (e: KeyboardEvent) => {\n const key = getKeyIdentifier(e.key);\n\n if (!filterFn(e)) {\n return;\n }\n\n // fix firefox behavior when caps lock fires three times onkeydown\n // and don't fire at all onkeyup (Firefox 72)\n if (isFirefox && key === CAPS_LOCK_KEY) {\n return;\n }\n\n modifiers = updateModifiers(e);\n\n // Check if key is not a modifier\n const isModifierKey =\n key === ('SHIFT' as KeyString) ||\n key === ('ALT' as KeyString) ||\n key === ('CTRL' as KeyString) ||\n key === ('META' as KeyString);\n if (!isModifierKey && !downKeys.has(key)) {\n downKeys.add(key);\n }\n // See if we need to ignore the keypress (filter() can can be overridden)\n // by default ignore key presses if a select, textarea, or input is focused\n // if (!assignKey.filter.call(this, event)) return;\n\n // abort if no potentially matching shortcuts found\n if (!(key in handlers)) {\n return;\n }\n\n const currentHandlers = handlers[key].filter(\n ({ scope, shortcut: { special, mods } }) => {\n if (scope !== activeScope) {\n return false;\n }\n\n return isEqArray(special, Array.from(downKeys)) && mods === modifiers;\n },\n );\n\n const primaryAction: Handler | undefined = currentHandlers.find(\n (action) => action.skipOther,\n );\n if (primaryAction) {\n primaryAction.method(e);\n } else {\n currentHandlers.forEach(({ method }) => {\n method(e);\n });\n }\n };\n\n const cleanUp = (e: KeyboardEvent) => {\n const key = getKeyIdentifier(e.key);\n\n // clean all for meta.\n // Main reason is ctrl+z (or any other native command not fires letter keyup on editable inputs)\n if (e.key && e.key.toLowerCase() === 'meta') {\n downKeys.clear();\n } else {\n downKeys.delete(key);\n }\n };\n\n const unbindScope = (deleteScope: string): void => {\n Object.keys(handlers).forEach((key) => {\n const keyString = key as KeyString;\n const handler = handlers[keyString].filter(\n ({ scope }: Handler) => scope !== deleteScope,\n );\n if (handler.length) {\n handlers[keyString] = handler;\n } else {\n delete handlers[keyString];\n }\n });\n };\n\n const setScope = (scope: string): void => {\n activeScope = scope;\n };\n\n const unbindAll = (): void => {\n handlers = {};\n downKeys.clear();\n };\n\n const reset = (): void => {\n downKeys.clear();\n };\n\n const destroy = (): void => {\n downKeys.clear();\n handlers = {};\n if (doc) {\n const listeners = documentListeners.get(doc);\n if (listeners) {\n doc.removeEventListener('keydown', listeners.dispatch);\n doc.removeEventListener('keyup', listeners.cleanUp);\n window.removeEventListener('focus', listeners.reset);\n documentListeners.delete(doc);\n }\n }\n };\n\n // Remove old listeners if they exist\n destroy();\n\n // Store and add new listeners\n documentListeners.set(doc, { dispatch, cleanUp, reset });\n doc.addEventListener('keydown', dispatch);\n doc.addEventListener('keyup', cleanUp);\n window.addEventListener('focus', reset);\n\n return {\n bind: bindKey,\n unbind: unbindKey,\n unsafeUnbind: unsafeUnbindKey,\n unbindScope,\n setScope,\n unbindAll,\n getScope: () => activeScope,\n destroy,\n };\n}\n","import { DEFAULT_SCOPE } from './constants';\nimport { createKeybuddy } from './keybuddy';\n\nconst {\n bind,\n unbind,\n unsafeUnbind,\n getScope,\n setScope,\n unbindScope,\n unbindAll,\n destroy,\n} = createKeybuddy(document);\n\nexport const bindKey = bind;\nexport const unbindKey = unbind;\nexport const unsafeUnbindKey = unsafeUnbind;\nexport { setScope, unbindScope, unbindAll, getScope, destroy, DEFAULT_SCOPE };\nexport type { KeyString } from './constants';\nexport default bind;\n"],"mappings":"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","names":["DEFAULT_SCOPE","MODS","MODIFIERS","SPECIAL","CAPS_LOCK_KEY","getKeyIdentifier","key","SPECIAL","updateModifiers","modifiers","MODS","getKeyIdentifier","key","SPECIAL","getMods","keys","acc","MODIFIERS","getCombinations","keysStr","getKeyMap","keyCmd","isFirefox","isEditable","el","isEqArray","arr1","arr2","i","defaultFilter","isEditable","documentListeners","createKeybuddy","doc","filterFn","handlers","downKeys","activeScope","modifiers","bindKey","keysStr","scopeOrMethod","methodOrNull","skipOther","scope","method","getKeyMap","key","shortcut","unbindKeyProcess","deleteMethod","deleteScope","handler","methodShortcut","isEqArray","unbindKey","unsafeUnbindKey","dispatch","e","getKeyIdentifier","isFirefox","CAPS_LOCK_KEY","updateModifiers","currentHandlers","special","mods","primaryAction","action","cleanUp","unbindScope","keyString","setScope","unbindAll","reset","destroy","listeners","bind","unbind","unsafeUnbind","getScope","setScope","unbindScope","unbindAll","destroy","createKeybuddy","bindKey","unbindKey","unsafeUnbindKey","src_default","bind"]}
@@ -1,15 +1,16 @@
1
- declare type noop = (e: KeyboardEvent) => void;
2
- declare type FilterFn = (el: KeyboardEvent) => boolean;
3
- declare const _default: (doc?: HTMLDocument | undefined, filterFn?: FilterFn) => {
4
- bind: (keysStr: string, scopeOrMethod: string | noop, methodOrNull?: noop, { skipOther }?: {
1
+ type noop = (e: KeyboardEvent) => void;
2
+ type FilterFn = (el: KeyboardEvent) => boolean;
3
+ declare function createKeybuddy(doc: Document, filterFn?: FilterFn): {
4
+ bind: (keysStr: string, scopeOrMethod: string | noop, methodOrNull?: noop, { skipOther, }?: {
5
5
  skipOther: boolean;
6
6
  }) => void;
7
7
  unbind: (keysStr: string, scopeOrMethod: string | noop, methodOrNull?: noop) => void;
8
- unsafeUnbind: (keysStr: string, scope?: string | undefined) => void;
8
+ unsafeUnbind: (keysStr: string, scope?: string) => void;
9
9
  unbindScope: (deleteScope: string) => void;
10
10
  setScope: (scope: string) => void;
11
11
  unbindAll: () => void;
12
12
  getScope: () => string;
13
13
  destroy: () => void;
14
14
  };
15
- export default _default;
15
+
16
+ export { createKeybuddy };
package/keybuddy.d.ts ADDED
@@ -0,0 +1,16 @@
1
+ type noop = (e: KeyboardEvent) => void;
2
+ type FilterFn = (el: KeyboardEvent) => boolean;
3
+ declare function createKeybuddy(doc: Document, filterFn?: FilterFn): {
4
+ bind: (keysStr: string, scopeOrMethod: string | noop, methodOrNull?: noop, { skipOther, }?: {
5
+ skipOther: boolean;
6
+ }) => void;
7
+ unbind: (keysStr: string, scopeOrMethod: string | noop, methodOrNull?: noop) => void;
8
+ unsafeUnbind: (keysStr: string, scope?: string) => void;
9
+ unbindScope: (deleteScope: string) => void;
10
+ setScope: (scope: string) => void;
11
+ unbindAll: () => void;
12
+ getScope: () => string;
13
+ destroy: () => void;
14
+ };
15
+
16
+ export { createKeybuddy };
@@ -0,0 +1,3 @@
1
+ /* keybuddy - Modern keyboard shortcuts library */
2
+ "use strict";var keybuddy=(()=>{var b=Object.defineProperty;var _=Object.getOwnPropertyDescriptor;var B=Object.getOwnPropertyNames;var q=Object.prototype.hasOwnProperty;var $=(e,r)=>{for(var t in r)b(e,t,{get:r[t],enumerable:!0})},V=(e,r,t,s)=>{if(r&&typeof r=="object"||typeof r=="function")for(let c of B(r))!q.call(e,c)&&c!==t&&b(e,c,{get:()=>r[c],enumerable:!(s=_(r,c))||s.enumerable});return e};var Y=e=>V(b({},"__esModule",{value:!0}),e);var G={};$(G,{createKeybuddy:()=>z});var i={SHIFT:1,ALT:2,CTRL:4,META:8},K={"\u21E7":i.SHIFT,shift:i.SHIFT,"\u2325":i.ALT,alt:i.ALT,option:i.ALT,"\u2303":i.CTRL,ctrl:i.CTRL,control:i.CTRL,"\u2318":i.META,cmd:i.META,command:i.META},u={backspace:"Backspace",tab:"Tab",clear:"Clear",enter:"Enter",return:"Enter",esc:"Escape",escape:"Escape",space:" ",left:"ArrowLeft",up:"ArrowUp",right:"ArrowRight",down:"ArrowDown",del:"Delete",delete:"Delete",home:"Home",end:"End",pageup:"PageUp",pagedown:"PageDown",comma:",",".":".","/":"/","`":"`","-":"-","=":"=",";":";","'":"'","[":"[","]":"]","\\":"\\",Meta:"Meta",MetaLeft:"Meta",MetaRight:"Meta",OS:"Meta",ContextMenu:"Meta",ArrowLeft:"ArrowLeft",ArrowUp:"ArrowUp",ArrowRight:"ArrowRight",ArrowDown:"ArrowDown",Backspace:"Backspace",Tab:"Tab",Clear:"Clear",Enter:"Enter",Escape:"Escape",Delete:"Delete",Home:"Home",End:"End",PageUp:"PageUp",PageDown:"PageDown"},x="CapsLock";var S=e=>u[e]||e.toUpperCase(),P=e=>{let r=0;return e.shiftKey&&(r|=i.SHIFT),e.altKey&&(r|=i.ALT),e.ctrlKey&&(r|=i.CTRL),e.metaKey&&(r|=i.META),r};var j=e=>u[e]||e.toUpperCase(),J=e=>e.reduce((r,t)=>(t in K?r.mods|=K[t]:r.special.push(u[t]||t.toUpperCase()),r),{mods:0,special:[]}),W=e=>{let t=e.replace(/\s/g,"").split(",");return t[t.length-1]===""&&(t[t.length-2]+=","),t},h=e=>W(e).map(t=>{let s=t.split("+"),c=s[s.length-1];return{key:j(c),shortcut:J(s)}});var D=navigator.userAgent.includes("Firefox"),I=e=>e.isContentEditable||e.tagName==="INPUT"||e.tagName==="SELECT"||e.tagName==="TEXTAREA",A=(e,r)=>{if(e.length!==r.length)return!1;for(let t=0;t<e.length;t++)if(e[t]!==r[t])return!1;return!0};var X=e=>e&&!I(e.target),v=new WeakMap;function z(e,r=X){let t={},s=new Set,c="all",m=0,F=(o,n,d=()=>{},{skipOther:a}={skipOther:!1})=>{let p=typeof n=="function"?"all":n,l=typeof n=="function"?n:d;h(o).forEach(({key:f,shortcut:g})=>{t[f]||(t[f]=[]),t[f].push({scope:p,method:l,shortcut:g,skipOther:a})})},L=(o,n,d="all")=>{h(o).forEach(({key:a,shortcut:p})=>{let l=t[a];if(Array.isArray(l)){let f=t[a].filter(({scope:g,method:C,shortcut:E})=>!(g===d&&E.mods===p.mods&&A(E.special,p.special)&&(n===null||C===n)));f.length?t[a]=f:delete t[a]}})},U=(o,n,d=()=>{})=>L(o,typeof n=="function"?n:d,typeof n=="function"?"all":n),H=(o,n)=>L(o,null,n),w=o=>{let n=S(o.key);if(!r(o)||D&&n===x||(m=P(o),!(n==="SHIFT"||n==="ALT"||n==="CTRL"||n==="META")&&!s.has(n)&&s.add(n),!(n in t)))return;let a=t[n].filter(({scope:l,shortcut:{special:f,mods:g}})=>l!==c?!1:A(f,Array.from(s))&&g===m),p=a.find(l=>l.skipOther);p?p.method(o):a.forEach(({method:l})=>{l(o)})},T=o=>{let n=S(o.key);o.key&&o.key.toLowerCase()==="meta"?s.clear():s.delete(n)},O=o=>{Object.keys(t).forEach(n=>{let d=n,a=t[d].filter(({scope:p})=>p!==o);a.length?t[d]=a:delete t[d]})},N=o=>{c=o},R=()=>{t={},s.clear()},M=()=>{s.clear()},k=()=>{if(s.clear(),t={},e){let o=v.get(e);o&&(e.removeEventListener("keydown",o.dispatch),e.removeEventListener("keyup",o.cleanUp),window.removeEventListener("focus",o.reset),v.delete(e))}};return k(),v.set(e,{dispatch:w,cleanUp:T,reset:M}),e.addEventListener("keydown",w),e.addEventListener("keyup",T),window.addEventListener("focus",M),{bind:F,unbind:U,unsafeUnbind:H,unbindScope:O,setScope:N,unbindAll:R,getScope:()=>c,destroy:k}}return Y(G);})();
3
+ //# sourceMappingURL=keybuddy.global.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/keybuddy.ts","../src/constants.ts","../src/helpers/keyboard.ts","../src/helpers/keymap.ts","../src/helpers/utils.ts"],"sourcesContent":["import { CAPS_LOCK_KEY, DEFAULT_SCOPE, KeyString } from './constants';\nimport { getKeyIdentifier, updateModifiers } from './helpers/keyboard';\nimport { getKeyMap, ParsedShortcut } from './helpers/keymap';\nimport { invariant, isEditable, isEqArray, isFirefox } from './helpers/utils';\n\ntype noop = (e: KeyboardEvent) => void;\ntype FilterFn = (el: KeyboardEvent) => boolean;\n\ninterface Handler {\n scope: string;\n method: noop;\n shortcut: ParsedShortcut;\n skipOther: boolean;\n}\n\nconst defaultFilter = (e: KeyboardEvent): boolean =>\n e && !isEditable(e.target as HTMLElement);\n\n// WeakMap to track event listener references per document to prevent memory leaks\nconst documentListeners = new WeakMap<\n Document,\n {\n dispatch: (e: KeyboardEvent) => void;\n cleanUp: (e: KeyboardEvent) => void;\n reset: () => void;\n }\n>();\n\nexport function createKeybuddy(\n doc: Document,\n filterFn: FilterFn = defaultFilter,\n) {\n let handlers: { [key: KeyString]: Handler[] } = {};\n const downKeys: Set<KeyString> = new Set();\n let activeScope = DEFAULT_SCOPE;\n\n let modifiers = 0; // Bitwise flag for active modifiers\n\n const bindKey = (\n keysStr: string,\n scopeOrMethod: string | noop,\n methodOrNull: noop = () => {},\n {\n skipOther,\n }: {\n skipOther: boolean;\n } = {\n skipOther: false,\n },\n ): void => {\n const scope: string =\n typeof scopeOrMethod === 'function' ? DEFAULT_SCOPE : scopeOrMethod;\n const method: noop =\n typeof scopeOrMethod === 'function' ? scopeOrMethod : methodOrNull;\n\n getKeyMap(keysStr).forEach(({ key, shortcut }) => {\n if (!handlers[key]) {\n handlers[key] = [];\n }\n const handler = handlers[key];\n if (process.env.NODE_ENV === 'development') {\n if (skipOther) {\n const action = handler.find((i) => i.skipOther);\n invariant(\n !action,\n \"Conflicting 'skipOther' property with action\",\n action,\n );\n }\n }\n\n handler.push({\n scope,\n method,\n shortcut,\n skipOther,\n });\n });\n };\n\n const unbindKeyProcess = (\n keysStr: string,\n deleteMethod: null | noop,\n deleteScope: string = DEFAULT_SCOPE,\n ): void => {\n getKeyMap(keysStr).forEach(({ key, shortcut }) => {\n const handler = handlers[key];\n if (Array.isArray(handler)) {\n const handler = handlers[key].filter(\n ({ scope, method, shortcut: methodShortcut }: Handler) =>\n !(\n scope === deleteScope &&\n methodShortcut.mods === shortcut.mods &&\n isEqArray(methodShortcut.special, shortcut.special) &&\n (deleteMethod === null ? true : method === deleteMethod)\n ),\n );\n if (handler.length) {\n handlers[key] = handler;\n } else {\n delete handlers[key];\n }\n }\n });\n };\n\n const unbindKey = (\n keysStr: string,\n scopeOrMethod: string | noop,\n methodOrNull: noop = () => {},\n ) => {\n const deleteScope: string =\n typeof scopeOrMethod === 'function' ? DEFAULT_SCOPE : scopeOrMethod;\n const deleteMethod: noop =\n typeof scopeOrMethod === 'function' ? scopeOrMethod : methodOrNull;\n return unbindKeyProcess(keysStr, deleteMethod, deleteScope);\n };\n\n const unsafeUnbindKey = (keysStr: string, scope?: string) =>\n unbindKeyProcess(keysStr, null, scope);\n\n const dispatch = (e: KeyboardEvent) => {\n const key = getKeyIdentifier(e.key);\n\n if (!filterFn(e)) {\n return;\n }\n\n // fix firefox behavior when caps lock fires three times onkeydown\n // and don't fire at all onkeyup (Firefox 72)\n if (isFirefox && key === CAPS_LOCK_KEY) {\n return;\n }\n\n modifiers = updateModifiers(e);\n\n // Check if key is not a modifier\n const isModifierKey =\n key === ('SHIFT' as KeyString) ||\n key === ('ALT' as KeyString) ||\n key === ('CTRL' as KeyString) ||\n key === ('META' as KeyString);\n if (!isModifierKey && !downKeys.has(key)) {\n downKeys.add(key);\n }\n // See if we need to ignore the keypress (filter() can can be overridden)\n // by default ignore key presses if a select, textarea, or input is focused\n // if (!assignKey.filter.call(this, event)) return;\n\n // abort if no potentially matching shortcuts found\n if (!(key in handlers)) {\n return;\n }\n\n const currentHandlers = handlers[key].filter(\n ({ scope, shortcut: { special, mods } }) => {\n if (scope !== activeScope) {\n return false;\n }\n\n return isEqArray(special, Array.from(downKeys)) && mods === modifiers;\n },\n );\n\n const primaryAction: Handler | undefined = currentHandlers.find(\n (action) => action.skipOther,\n );\n if (primaryAction) {\n primaryAction.method(e);\n } else {\n currentHandlers.forEach(({ method }) => {\n method(e);\n });\n }\n };\n\n const cleanUp = (e: KeyboardEvent) => {\n const key = getKeyIdentifier(e.key);\n\n // clean all for meta.\n // Main reason is ctrl+z (or any other native command not fires letter keyup on editable inputs)\n if (e.key && e.key.toLowerCase() === 'meta') {\n downKeys.clear();\n } else {\n downKeys.delete(key);\n }\n };\n\n const unbindScope = (deleteScope: string): void => {\n Object.keys(handlers).forEach((key) => {\n const keyString = key as KeyString;\n const handler = handlers[keyString].filter(\n ({ scope }: Handler) => scope !== deleteScope,\n );\n if (handler.length) {\n handlers[keyString] = handler;\n } else {\n delete handlers[keyString];\n }\n });\n };\n\n const setScope = (scope: string): void => {\n activeScope = scope;\n };\n\n const unbindAll = (): void => {\n handlers = {};\n downKeys.clear();\n };\n\n const reset = (): void => {\n downKeys.clear();\n };\n\n const destroy = (): void => {\n downKeys.clear();\n handlers = {};\n if (doc) {\n const listeners = documentListeners.get(doc);\n if (listeners) {\n doc.removeEventListener('keydown', listeners.dispatch);\n doc.removeEventListener('keyup', listeners.cleanUp);\n window.removeEventListener('focus', listeners.reset);\n documentListeners.delete(doc);\n }\n }\n };\n\n // Remove old listeners if they exist\n destroy();\n\n // Store and add new listeners\n documentListeners.set(doc, { dispatch, cleanUp, reset });\n doc.addEventListener('keydown', dispatch);\n doc.addEventListener('keyup', cleanUp);\n window.addEventListener('focus', reset);\n\n return {\n bind: bindKey,\n unbind: unbindKey,\n unsafeUnbind: unsafeUnbindKey,\n unbindScope,\n setScope,\n unbindAll,\n getScope: () => activeScope,\n destroy,\n };\n}\n","\nexport const DEFAULT_SCOPE = 'all';\n\ndeclare const KeyStringBrand: unique symbol;\n\nexport type KeyString = string & { readonly [KeyStringBrand]: true };\n\n// Bitwise flags for modifiers - much faster than object-based tracking\nexport const MODS = {\n SHIFT: 0b0001, // 1\n ALT: 0b0010, // 2\n CTRL: 0b0100, // 4\n META: 0b1000, // 8\n} as const;\n\n// Map string modifier names to bitwise flags for parsing\nexport type ModifierNames = {\n '⇧': number;\n shift: number;\n '⌥': number;\n alt: number;\n option: number;\n '⌃': number;\n ctrl: number;\n control: number;\n '⌘': number;\n cmd: number;\n command: number;\n};\n\nexport const MODIFIERS: ModifierNames = {\n '⇧': MODS.SHIFT,\n shift: MODS.SHIFT,\n '⌥': MODS.ALT,\n alt: MODS.ALT,\n option: MODS.ALT,\n '⌃': MODS.CTRL,\n ctrl: MODS.CTRL,\n control: MODS.CTRL,\n '⌘': MODS.META,\n cmd: MODS.META,\n command: MODS.META,\n};\n\n// Modern key mapping using KeyboardEvent.key values\nexport const SPECIAL: { [key: string]: string } = {\n backspace: 'Backspace',\n tab: 'Tab',\n clear: 'Clear',\n enter: 'Enter',\n return: 'Enter',\n esc: 'Escape',\n escape: 'Escape',\n space: ' ',\n left: 'ArrowLeft',\n up: 'ArrowUp',\n right: 'ArrowRight',\n down: 'ArrowDown',\n del: 'Delete',\n delete: 'Delete',\n home: 'Home',\n end: 'End',\n pageup: 'PageUp',\n pagedown: 'PageDown',\n comma: ',',\n '.': '.',\n '/': '/',\n '`': '`',\n '-': '-',\n '=': '=',\n ';': ';',\n \"'\": \"'\",\n '[': '[',\n ']': ']',\n '\\\\': '\\\\',\n // Normalize Meta key variants\n 'Meta': 'Meta',\n 'MetaLeft': 'Meta',\n 'MetaRight': 'Meta', \n 'OS': 'Meta', // Some browsers use OS instead of Meta\n 'ContextMenu': 'Meta', // Right-click context menu key sometimes acts as Meta\n // Add identity mappings for already-normalized keys\n 'ArrowLeft': 'ArrowLeft',\n 'ArrowUp': 'ArrowUp',\n 'ArrowRight': 'ArrowRight',\n 'ArrowDown': 'ArrowDown',\n 'Backspace': 'Backspace',\n 'Tab': 'Tab',\n 'Clear': 'Clear',\n 'Enter': 'Enter',\n 'Escape': 'Escape',\n 'Delete': 'Delete',\n 'Home': 'Home',\n 'End': 'End',\n 'PageUp': 'PageUp',\n 'PageDown': 'PageDown',\n};\n\nexport const CAPS_LOCK_KEY = 'CapsLock';\n","import { KeyString, MODS, SPECIAL } from '../constants';\n\nexport const getKeyIdentifier = (key: string): KeyString => {\n return (SPECIAL[key] || key.toUpperCase()) as KeyString;\n};\n\nexport const updateModifiers = (e: KeyboardEvent): number => {\n let modifiers = 0;\n if (e.shiftKey) modifiers |= MODS.SHIFT;\n if (e.altKey) modifiers |= MODS.ALT;\n if (e.ctrlKey) modifiers |= MODS.CTRL;\n if (e.metaKey) modifiers |= MODS.META;\n return modifiers;\n};\n","import { KeyString, MODIFIERS, ModifierNames, SPECIAL } from '../constants';\n\nexport interface ParsedShortcut {\n mods: number; // Bitwise flag for modifiers\n special: string[];\n}\nexport interface KeyMap {\n key: KeyString;\n shortcut: ParsedShortcut;\n}\n\nexport const getKeyIdentifier = (key: string): KeyString =>\n (SPECIAL[key] || key.toUpperCase()) as KeyString;\n\nconst getMods = (keys: string[]): ParsedShortcut =>\n keys.reduce(\n (acc, key) => {\n if (key in MODIFIERS) {\n acc.mods |= MODIFIERS[key as keyof ModifierNames];\n } else {\n acc.special.push(SPECIAL[key] || key.toUpperCase());\n }\n return acc;\n },\n {\n mods: 0, // Start with no modifiers\n special: [],\n } as ParsedShortcut,\n );\n\nconst getCombinations = (keysStr: string): string[] => {\n const cleanKeys = keysStr.replace(/\\s/g, '');\n const keys = cleanKeys.split(',');\n if (keys[keys.length - 1] === '') {\n keys[keys.length - 2] += ',';\n }\n\n return keys;\n};\n\nexport const getKeyMap = (keysStr: string): KeyMap[] => {\n const keymap = getCombinations(keysStr);\n return keymap.map((keyCmd) => {\n const keys = keyCmd.split('+');\n const key = keys[keys.length - 1];\n const keyIdentifier = getKeyIdentifier(key);\n\n return {\n key: keyIdentifier,\n shortcut: getMods(keys),\n };\n });\n};\n","export const invariant = (\n condition: boolean,\n message: string,\n ...args: unknown[]\n) => {\n if (\n typeof process !== 'undefined' &&\n process.env &&\n process.env.NODE_ENV === 'development' &&\n !condition\n ) {\n throw new Error(\n `Invariant failed: ${message}${args.length ? ` ${JSON.stringify(args)}` : ''}`,\n );\n }\n};\n\nexport const isFirefox = navigator.userAgent.includes('Firefox');\n\nexport const isEditable = (el: HTMLElement): boolean =>\n el.isContentEditable ||\n el.tagName === 'INPUT' ||\n el.tagName === 'SELECT' ||\n el.tagName === 'TEXTAREA';\n\nexport const isEqArray = (\n arr1: (string | number)[],\n arr2: (string | number)[],\n): boolean => {\n if (arr1.length !== arr2.length) return false;\n\n for (let i = 0; i < arr1.length; i++) {\n if (arr1[i] !== arr2[i]) return false;\n }\n\n return true;\n};\n"],"mappings":"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","names":["keybuddy_exports","__export","createKeybuddy","MODS","MODIFIERS","SPECIAL","CAPS_LOCK_KEY","getKeyIdentifier","key","SPECIAL","updateModifiers","modifiers","MODS","getKeyIdentifier","key","SPECIAL","getMods","keys","acc","MODIFIERS","getCombinations","keysStr","getKeyMap","keyCmd","isFirefox","isEditable","el","isEqArray","arr1","arr2","i","defaultFilter","isEditable","documentListeners","createKeybuddy","doc","filterFn","handlers","downKeys","activeScope","modifiers","bindKey","keysStr","scopeOrMethod","methodOrNull","skipOther","scope","method","getKeyMap","key","shortcut","unbindKeyProcess","deleteMethod","deleteScope","handler","methodShortcut","isEqArray","unbindKey","unsafeUnbindKey","dispatch","e","getKeyIdentifier","isFirefox","CAPS_LOCK_KEY","updateModifiers","currentHandlers","special","mods","primaryAction","action","cleanUp","unbindScope","keyString","setScope","unbindAll","reset","destroy","listeners"]}
package/keybuddy.js ADDED
@@ -0,0 +1,3 @@
1
+ /* keybuddy - Modern keyboard shortcuts library */
2
+ "use strict";var b=Object.defineProperty;var _=Object.getOwnPropertyDescriptor;var B=Object.getOwnPropertyNames;var q=Object.prototype.hasOwnProperty;var $=(e,r)=>{for(var t in r)b(e,t,{get:r[t],enumerable:!0})},V=(e,r,t,s)=>{if(r&&typeof r=="object"||typeof r=="function")for(let c of B(r))!q.call(e,c)&&c!==t&&b(e,c,{get:()=>r[c],enumerable:!(s=_(r,c))||s.enumerable});return e};var Y=e=>V(b({},"__esModule",{value:!0}),e);var G={};$(G,{createKeybuddy:()=>z});module.exports=Y(G);var i={SHIFT:1,ALT:2,CTRL:4,META:8},K={"\u21E7":i.SHIFT,shift:i.SHIFT,"\u2325":i.ALT,alt:i.ALT,option:i.ALT,"\u2303":i.CTRL,ctrl:i.CTRL,control:i.CTRL,"\u2318":i.META,cmd:i.META,command:i.META},u={backspace:"Backspace",tab:"Tab",clear:"Clear",enter:"Enter",return:"Enter",esc:"Escape",escape:"Escape",space:" ",left:"ArrowLeft",up:"ArrowUp",right:"ArrowRight",down:"ArrowDown",del:"Delete",delete:"Delete",home:"Home",end:"End",pageup:"PageUp",pagedown:"PageDown",comma:",",".":".","/":"/","`":"`","-":"-","=":"=",";":";","'":"'","[":"[","]":"]","\\":"\\",Meta:"Meta",MetaLeft:"Meta",MetaRight:"Meta",OS:"Meta",ContextMenu:"Meta",ArrowLeft:"ArrowLeft",ArrowUp:"ArrowUp",ArrowRight:"ArrowRight",ArrowDown:"ArrowDown",Backspace:"Backspace",Tab:"Tab",Clear:"Clear",Enter:"Enter",Escape:"Escape",Delete:"Delete",Home:"Home",End:"End",PageUp:"PageUp",PageDown:"PageDown"},x="CapsLock";var S=e=>u[e]||e.toUpperCase(),P=e=>{let r=0;return e.shiftKey&&(r|=i.SHIFT),e.altKey&&(r|=i.ALT),e.ctrlKey&&(r|=i.CTRL),e.metaKey&&(r|=i.META),r};var j=e=>u[e]||e.toUpperCase(),J=e=>e.reduce((r,t)=>(t in K?r.mods|=K[t]:r.special.push(u[t]||t.toUpperCase()),r),{mods:0,special:[]}),W=e=>{let t=e.replace(/\s/g,"").split(",");return t[t.length-1]===""&&(t[t.length-2]+=","),t},h=e=>W(e).map(t=>{let s=t.split("+"),c=s[s.length-1];return{key:j(c),shortcut:J(s)}});var D=navigator.userAgent.includes("Firefox"),I=e=>e.isContentEditable||e.tagName==="INPUT"||e.tagName==="SELECT"||e.tagName==="TEXTAREA",A=(e,r)=>{if(e.length!==r.length)return!1;for(let t=0;t<e.length;t++)if(e[t]!==r[t])return!1;return!0};var X=e=>e&&!I(e.target),v=new WeakMap;function z(e,r=X){let t={},s=new Set,c="all",m=0,F=(o,n,d=()=>{},{skipOther:a}={skipOther:!1})=>{let p=typeof n=="function"?"all":n,l=typeof n=="function"?n:d;h(o).forEach(({key:f,shortcut:g})=>{t[f]||(t[f]=[]),t[f].push({scope:p,method:l,shortcut:g,skipOther:a})})},L=(o,n,d="all")=>{h(o).forEach(({key:a,shortcut:p})=>{let l=t[a];if(Array.isArray(l)){let f=t[a].filter(({scope:g,method:C,shortcut:E})=>!(g===d&&E.mods===p.mods&&A(E.special,p.special)&&(n===null||C===n)));f.length?t[a]=f:delete t[a]}})},U=(o,n,d=()=>{})=>L(o,typeof n=="function"?n:d,typeof n=="function"?"all":n),H=(o,n)=>L(o,null,n),w=o=>{let n=S(o.key);if(!r(o)||D&&n===x||(m=P(o),!(n==="SHIFT"||n==="ALT"||n==="CTRL"||n==="META")&&!s.has(n)&&s.add(n),!(n in t)))return;let a=t[n].filter(({scope:l,shortcut:{special:f,mods:g}})=>l!==c?!1:A(f,Array.from(s))&&g===m),p=a.find(l=>l.skipOther);p?p.method(o):a.forEach(({method:l})=>{l(o)})},T=o=>{let n=S(o.key);o.key&&o.key.toLowerCase()==="meta"?s.clear():s.delete(n)},O=o=>{Object.keys(t).forEach(n=>{let d=n,a=t[d].filter(({scope:p})=>p!==o);a.length?t[d]=a:delete t[d]})},N=o=>{c=o},R=()=>{t={},s.clear()},M=()=>{s.clear()},k=()=>{if(s.clear(),t={},e){let o=v.get(e);o&&(e.removeEventListener("keydown",o.dispatch),e.removeEventListener("keyup",o.cleanUp),window.removeEventListener("focus",o.reset),v.delete(e))}};return k(),v.set(e,{dispatch:w,cleanUp:T,reset:M}),e.addEventListener("keydown",w),e.addEventListener("keyup",T),window.addEventListener("focus",M),{bind:F,unbind:U,unsafeUnbind:H,unbindScope:O,setScope:N,unbindAll:R,getScope:()=>c,destroy:k}}0&&(module.exports={createKeybuddy});
3
+ //# sourceMappingURL=keybuddy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/keybuddy.ts","../src/constants.ts","../src/helpers/keyboard.ts","../src/helpers/keymap.ts","../src/helpers/utils.ts"],"sourcesContent":["import { CAPS_LOCK_KEY, DEFAULT_SCOPE, KeyString } from './constants';\nimport { getKeyIdentifier, updateModifiers } from './helpers/keyboard';\nimport { getKeyMap, ParsedShortcut } from './helpers/keymap';\nimport { invariant, isEditable, isEqArray, isFirefox } from './helpers/utils';\n\ntype noop = (e: KeyboardEvent) => void;\ntype FilterFn = (el: KeyboardEvent) => boolean;\n\ninterface Handler {\n scope: string;\n method: noop;\n shortcut: ParsedShortcut;\n skipOther: boolean;\n}\n\nconst defaultFilter = (e: KeyboardEvent): boolean =>\n e && !isEditable(e.target as HTMLElement);\n\n// WeakMap to track event listener references per document to prevent memory leaks\nconst documentListeners = new WeakMap<\n Document,\n {\n dispatch: (e: KeyboardEvent) => void;\n cleanUp: (e: KeyboardEvent) => void;\n reset: () => void;\n }\n>();\n\nexport function createKeybuddy(\n doc: Document,\n filterFn: FilterFn = defaultFilter,\n) {\n let handlers: { [key: KeyString]: Handler[] } = {};\n const downKeys: Set<KeyString> = new Set();\n let activeScope = DEFAULT_SCOPE;\n\n let modifiers = 0; // Bitwise flag for active modifiers\n\n const bindKey = (\n keysStr: string,\n scopeOrMethod: string | noop,\n methodOrNull: noop = () => {},\n {\n skipOther,\n }: {\n skipOther: boolean;\n } = {\n skipOther: false,\n },\n ): void => {\n const scope: string =\n typeof scopeOrMethod === 'function' ? DEFAULT_SCOPE : scopeOrMethod;\n const method: noop =\n typeof scopeOrMethod === 'function' ? scopeOrMethod : methodOrNull;\n\n getKeyMap(keysStr).forEach(({ key, shortcut }) => {\n if (!handlers[key]) {\n handlers[key] = [];\n }\n const handler = handlers[key];\n if (process.env.NODE_ENV === 'development') {\n if (skipOther) {\n const action = handler.find((i) => i.skipOther);\n invariant(\n !action,\n \"Conflicting 'skipOther' property with action\",\n action,\n );\n }\n }\n\n handler.push({\n scope,\n method,\n shortcut,\n skipOther,\n });\n });\n };\n\n const unbindKeyProcess = (\n keysStr: string,\n deleteMethod: null | noop,\n deleteScope: string = DEFAULT_SCOPE,\n ): void => {\n getKeyMap(keysStr).forEach(({ key, shortcut }) => {\n const handler = handlers[key];\n if (Array.isArray(handler)) {\n const handler = handlers[key].filter(\n ({ scope, method, shortcut: methodShortcut }: Handler) =>\n !(\n scope === deleteScope &&\n methodShortcut.mods === shortcut.mods &&\n isEqArray(methodShortcut.special, shortcut.special) &&\n (deleteMethod === null ? true : method === deleteMethod)\n ),\n );\n if (handler.length) {\n handlers[key] = handler;\n } else {\n delete handlers[key];\n }\n }\n });\n };\n\n const unbindKey = (\n keysStr: string,\n scopeOrMethod: string | noop,\n methodOrNull: noop = () => {},\n ) => {\n const deleteScope: string =\n typeof scopeOrMethod === 'function' ? DEFAULT_SCOPE : scopeOrMethod;\n const deleteMethod: noop =\n typeof scopeOrMethod === 'function' ? scopeOrMethod : methodOrNull;\n return unbindKeyProcess(keysStr, deleteMethod, deleteScope);\n };\n\n const unsafeUnbindKey = (keysStr: string, scope?: string) =>\n unbindKeyProcess(keysStr, null, scope);\n\n const dispatch = (e: KeyboardEvent) => {\n const key = getKeyIdentifier(e.key);\n\n if (!filterFn(e)) {\n return;\n }\n\n // fix firefox behavior when caps lock fires three times onkeydown\n // and don't fire at all onkeyup (Firefox 72)\n if (isFirefox && key === CAPS_LOCK_KEY) {\n return;\n }\n\n modifiers = updateModifiers(e);\n\n // Check if key is not a modifier\n const isModifierKey =\n key === ('SHIFT' as KeyString) ||\n key === ('ALT' as KeyString) ||\n key === ('CTRL' as KeyString) ||\n key === ('META' as KeyString);\n if (!isModifierKey && !downKeys.has(key)) {\n downKeys.add(key);\n }\n // See if we need to ignore the keypress (filter() can can be overridden)\n // by default ignore key presses if a select, textarea, or input is focused\n // if (!assignKey.filter.call(this, event)) return;\n\n // abort if no potentially matching shortcuts found\n if (!(key in handlers)) {\n return;\n }\n\n const currentHandlers = handlers[key].filter(\n ({ scope, shortcut: { special, mods } }) => {\n if (scope !== activeScope) {\n return false;\n }\n\n return isEqArray(special, Array.from(downKeys)) && mods === modifiers;\n },\n );\n\n const primaryAction: Handler | undefined = currentHandlers.find(\n (action) => action.skipOther,\n );\n if (primaryAction) {\n primaryAction.method(e);\n } else {\n currentHandlers.forEach(({ method }) => {\n method(e);\n });\n }\n };\n\n const cleanUp = (e: KeyboardEvent) => {\n const key = getKeyIdentifier(e.key);\n\n // clean all for meta.\n // Main reason is ctrl+z (or any other native command not fires letter keyup on editable inputs)\n if (e.key && e.key.toLowerCase() === 'meta') {\n downKeys.clear();\n } else {\n downKeys.delete(key);\n }\n };\n\n const unbindScope = (deleteScope: string): void => {\n Object.keys(handlers).forEach((key) => {\n const keyString = key as KeyString;\n const handler = handlers[keyString].filter(\n ({ scope }: Handler) => scope !== deleteScope,\n );\n if (handler.length) {\n handlers[keyString] = handler;\n } else {\n delete handlers[keyString];\n }\n });\n };\n\n const setScope = (scope: string): void => {\n activeScope = scope;\n };\n\n const unbindAll = (): void => {\n handlers = {};\n downKeys.clear();\n };\n\n const reset = (): void => {\n downKeys.clear();\n };\n\n const destroy = (): void => {\n downKeys.clear();\n handlers = {};\n if (doc) {\n const listeners = documentListeners.get(doc);\n if (listeners) {\n doc.removeEventListener('keydown', listeners.dispatch);\n doc.removeEventListener('keyup', listeners.cleanUp);\n window.removeEventListener('focus', listeners.reset);\n documentListeners.delete(doc);\n }\n }\n };\n\n // Remove old listeners if they exist\n destroy();\n\n // Store and add new listeners\n documentListeners.set(doc, { dispatch, cleanUp, reset });\n doc.addEventListener('keydown', dispatch);\n doc.addEventListener('keyup', cleanUp);\n window.addEventListener('focus', reset);\n\n return {\n bind: bindKey,\n unbind: unbindKey,\n unsafeUnbind: unsafeUnbindKey,\n unbindScope,\n setScope,\n unbindAll,\n getScope: () => activeScope,\n destroy,\n };\n}\n","\nexport const DEFAULT_SCOPE = 'all';\n\ndeclare const KeyStringBrand: unique symbol;\n\nexport type KeyString = string & { readonly [KeyStringBrand]: true };\n\n// Bitwise flags for modifiers - much faster than object-based tracking\nexport const MODS = {\n SHIFT: 0b0001, // 1\n ALT: 0b0010, // 2\n CTRL: 0b0100, // 4\n META: 0b1000, // 8\n} as const;\n\n// Map string modifier names to bitwise flags for parsing\nexport type ModifierNames = {\n '⇧': number;\n shift: number;\n '⌥': number;\n alt: number;\n option: number;\n '⌃': number;\n ctrl: number;\n control: number;\n '⌘': number;\n cmd: number;\n command: number;\n};\n\nexport const MODIFIERS: ModifierNames = {\n '⇧': MODS.SHIFT,\n shift: MODS.SHIFT,\n '⌥': MODS.ALT,\n alt: MODS.ALT,\n option: MODS.ALT,\n '⌃': MODS.CTRL,\n ctrl: MODS.CTRL,\n control: MODS.CTRL,\n '⌘': MODS.META,\n cmd: MODS.META,\n command: MODS.META,\n};\n\n// Modern key mapping using KeyboardEvent.key values\nexport const SPECIAL: { [key: string]: string } = {\n backspace: 'Backspace',\n tab: 'Tab',\n clear: 'Clear',\n enter: 'Enter',\n return: 'Enter',\n esc: 'Escape',\n escape: 'Escape',\n space: ' ',\n left: 'ArrowLeft',\n up: 'ArrowUp',\n right: 'ArrowRight',\n down: 'ArrowDown',\n del: 'Delete',\n delete: 'Delete',\n home: 'Home',\n end: 'End',\n pageup: 'PageUp',\n pagedown: 'PageDown',\n comma: ',',\n '.': '.',\n '/': '/',\n '`': '`',\n '-': '-',\n '=': '=',\n ';': ';',\n \"'\": \"'\",\n '[': '[',\n ']': ']',\n '\\\\': '\\\\',\n // Normalize Meta key variants\n 'Meta': 'Meta',\n 'MetaLeft': 'Meta',\n 'MetaRight': 'Meta', \n 'OS': 'Meta', // Some browsers use OS instead of Meta\n 'ContextMenu': 'Meta', // Right-click context menu key sometimes acts as Meta\n // Add identity mappings for already-normalized keys\n 'ArrowLeft': 'ArrowLeft',\n 'ArrowUp': 'ArrowUp',\n 'ArrowRight': 'ArrowRight',\n 'ArrowDown': 'ArrowDown',\n 'Backspace': 'Backspace',\n 'Tab': 'Tab',\n 'Clear': 'Clear',\n 'Enter': 'Enter',\n 'Escape': 'Escape',\n 'Delete': 'Delete',\n 'Home': 'Home',\n 'End': 'End',\n 'PageUp': 'PageUp',\n 'PageDown': 'PageDown',\n};\n\nexport const CAPS_LOCK_KEY = 'CapsLock';\n","import { KeyString, MODS, SPECIAL } from '../constants';\n\nexport const getKeyIdentifier = (key: string): KeyString => {\n return (SPECIAL[key] || key.toUpperCase()) as KeyString;\n};\n\nexport const updateModifiers = (e: KeyboardEvent): number => {\n let modifiers = 0;\n if (e.shiftKey) modifiers |= MODS.SHIFT;\n if (e.altKey) modifiers |= MODS.ALT;\n if (e.ctrlKey) modifiers |= MODS.CTRL;\n if (e.metaKey) modifiers |= MODS.META;\n return modifiers;\n};\n","import { KeyString, MODIFIERS, ModifierNames, SPECIAL } from '../constants';\n\nexport interface ParsedShortcut {\n mods: number; // Bitwise flag for modifiers\n special: string[];\n}\nexport interface KeyMap {\n key: KeyString;\n shortcut: ParsedShortcut;\n}\n\nexport const getKeyIdentifier = (key: string): KeyString =>\n (SPECIAL[key] || key.toUpperCase()) as KeyString;\n\nconst getMods = (keys: string[]): ParsedShortcut =>\n keys.reduce(\n (acc, key) => {\n if (key in MODIFIERS) {\n acc.mods |= MODIFIERS[key as keyof ModifierNames];\n } else {\n acc.special.push(SPECIAL[key] || key.toUpperCase());\n }\n return acc;\n },\n {\n mods: 0, // Start with no modifiers\n special: [],\n } as ParsedShortcut,\n );\n\nconst getCombinations = (keysStr: string): string[] => {\n const cleanKeys = keysStr.replace(/\\s/g, '');\n const keys = cleanKeys.split(',');\n if (keys[keys.length - 1] === '') {\n keys[keys.length - 2] += ',';\n }\n\n return keys;\n};\n\nexport const getKeyMap = (keysStr: string): KeyMap[] => {\n const keymap = getCombinations(keysStr);\n return keymap.map((keyCmd) => {\n const keys = keyCmd.split('+');\n const key = keys[keys.length - 1];\n const keyIdentifier = getKeyIdentifier(key);\n\n return {\n key: keyIdentifier,\n shortcut: getMods(keys),\n };\n });\n};\n","export const invariant = (\n condition: boolean,\n message: string,\n ...args: unknown[]\n) => {\n if (\n typeof process !== 'undefined' &&\n process.env &&\n process.env.NODE_ENV === 'development' &&\n !condition\n ) {\n throw new Error(\n `Invariant failed: ${message}${args.length ? ` ${JSON.stringify(args)}` : ''}`,\n );\n }\n};\n\nexport const isFirefox = navigator.userAgent.includes('Firefox');\n\nexport const isEditable = (el: HTMLElement): boolean =>\n el.isContentEditable ||\n el.tagName === 'INPUT' ||\n el.tagName === 'SELECT' ||\n el.tagName === 'TEXTAREA';\n\nexport const isEqArray = (\n arr1: (string | number)[],\n arr2: (string | number)[],\n): boolean => {\n if (arr1.length !== arr2.length) return false;\n\n for (let i = 0; i < arr1.length; i++) {\n if (arr1[i] !== arr2[i]) return false;\n }\n\n return true;\n};\n"],"mappings":"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","names":["keybuddy_exports","__export","createKeybuddy","__toCommonJS","MODS","MODIFIERS","SPECIAL","CAPS_LOCK_KEY","getKeyIdentifier","key","SPECIAL","updateModifiers","modifiers","MODS","getKeyIdentifier","key","SPECIAL","getMods","keys","acc","MODIFIERS","getCombinations","keysStr","getKeyMap","keyCmd","isFirefox","isEditable","el","isEqArray","arr1","arr2","i","defaultFilter","isEditable","documentListeners","createKeybuddy","doc","filterFn","handlers","downKeys","activeScope","modifiers","bindKey","keysStr","scopeOrMethod","methodOrNull","skipOther","scope","method","getKeyMap","key","shortcut","unbindKeyProcess","deleteMethod","deleteScope","handler","methodShortcut","isEqArray","unbindKey","unsafeUnbindKey","dispatch","e","getKeyIdentifier","isFirefox","CAPS_LOCK_KEY","updateModifiers","currentHandlers","special","mods","primaryAction","action","cleanUp","unbindScope","keyString","setScope","unbindAll","reset","destroy","listeners"]}
package/keybuddy.mjs ADDED
@@ -0,0 +1,3 @@
1
+ /* keybuddy - Modern keyboard shortcuts library */
2
+ var i={SHIFT:1,ALT:2,CTRL:4,META:8},b={"\u21E7":i.SHIFT,shift:i.SHIFT,"\u2325":i.ALT,alt:i.ALT,option:i.ALT,"\u2303":i.CTRL,ctrl:i.CTRL,control:i.CTRL,"\u2318":i.META,cmd:i.META,command:i.META},u={backspace:"Backspace",tab:"Tab",clear:"Clear",enter:"Enter",return:"Enter",esc:"Escape",escape:"Escape",space:" ",left:"ArrowLeft",up:"ArrowUp",right:"ArrowRight",down:"ArrowDown",del:"Delete",delete:"Delete",home:"Home",end:"End",pageup:"PageUp",pagedown:"PageDown",comma:",",".":".","/":"/","`":"`","-":"-","=":"=",";":";","'":"'","[":"[","]":"]","\\":"\\",Meta:"Meta",MetaLeft:"Meta",MetaRight:"Meta",OS:"Meta",ContextMenu:"Meta",ArrowLeft:"ArrowLeft",ArrowUp:"ArrowUp",ArrowRight:"ArrowRight",ArrowDown:"ArrowDown",Backspace:"Backspace",Tab:"Tab",Clear:"Clear",Enter:"Enter",Escape:"Escape",Delete:"Delete",Home:"Home",End:"End",PageUp:"PageUp",PageDown:"PageDown"},C="CapsLock";var K=e=>u[e]||e.toUpperCase(),x=e=>{let o=0;return e.shiftKey&&(o|=i.SHIFT),e.altKey&&(o|=i.ALT),e.ctrlKey&&(o|=i.CTRL),e.metaKey&&(o|=i.META),o};var R=e=>u[e]||e.toUpperCase(),_=e=>e.reduce((o,t)=>(t in b?o.mods|=b[t]:o.special.push(u[t]||t.toUpperCase()),o),{mods:0,special:[]}),B=e=>{let t=e.replace(/\s/g,"").split(",");return t[t.length-1]===""&&(t[t.length-2]+=","),t},S=e=>B(e).map(t=>{let a=t.split("+"),f=a[a.length-1];return{key:R(f),shortcut:_(a)}});var P=navigator.userAgent.includes("Firefox"),D=e=>e.isContentEditable||e.tagName==="INPUT"||e.tagName==="SELECT"||e.tagName==="TEXTAREA",h=(e,o)=>{if(e.length!==o.length)return!1;for(let t=0;t<e.length;t++)if(e[t]!==o[t])return!1;return!0};var q=e=>e&&!D(e.target),A=new WeakMap;function se(e,o=q){let t={},a=new Set,f="all",m=0,I=(r,n,c=()=>{},{skipOther:s}={skipOther:!1})=>{let d=typeof n=="function"?"all":n,p=typeof n=="function"?n:c;S(r).forEach(({key:l,shortcut:g})=>{t[l]||(t[l]=[]),t[l].push({scope:d,method:p,shortcut:g,skipOther:s})})},v=(r,n,c="all")=>{S(r).forEach(({key:s,shortcut:d})=>{let p=t[s];if(Array.isArray(p)){let l=t[s].filter(({scope:g,method:k,shortcut:E})=>!(g===c&&E.mods===d.mods&&h(E.special,d.special)&&(n===null||k===n)));l.length?t[s]=l:delete t[s]}})},F=(r,n,c=()=>{})=>v(r,typeof n=="function"?n:c,typeof n=="function"?"all":n),U=(r,n)=>v(r,null,n),L=r=>{let n=K(r.key);if(!o(r)||P&&n===C||(m=x(r),!(n==="SHIFT"||n==="ALT"||n==="CTRL"||n==="META")&&!a.has(n)&&a.add(n),!(n in t)))return;let s=t[n].filter(({scope:p,shortcut:{special:l,mods:g}})=>p!==f?!1:h(l,Array.from(a))&&g===m),d=s.find(p=>p.skipOther);d?d.method(r):s.forEach(({method:p})=>{p(r)})},w=r=>{let n=K(r.key);r.key&&r.key.toLowerCase()==="meta"?a.clear():a.delete(n)},H=r=>{Object.keys(t).forEach(n=>{let c=n,s=t[c].filter(({scope:d})=>d!==r);s.length?t[c]=s:delete t[c]})},O=r=>{f=r},N=()=>{t={},a.clear()},T=()=>{a.clear()},M=()=>{if(a.clear(),t={},e){let r=A.get(e);r&&(e.removeEventListener("keydown",r.dispatch),e.removeEventListener("keyup",r.cleanUp),window.removeEventListener("focus",r.reset),A.delete(e))}};return M(),A.set(e,{dispatch:L,cleanUp:w,reset:T}),e.addEventListener("keydown",L),e.addEventListener("keyup",w),window.addEventListener("focus",T),{bind:I,unbind:F,unsafeUnbind:U,unbindScope:H,setScope:O,unbindAll:N,getScope:()=>f,destroy:M}}export{se as createKeybuddy};
3
+ //# sourceMappingURL=keybuddy.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/constants.ts","../src/helpers/keyboard.ts","../src/helpers/keymap.ts","../src/helpers/utils.ts","../src/keybuddy.ts"],"sourcesContent":["\nexport const DEFAULT_SCOPE = 'all';\n\ndeclare const KeyStringBrand: unique symbol;\n\nexport type KeyString = string & { readonly [KeyStringBrand]: true };\n\n// Bitwise flags for modifiers - much faster than object-based tracking\nexport const MODS = {\n SHIFT: 0b0001, // 1\n ALT: 0b0010, // 2\n CTRL: 0b0100, // 4\n META: 0b1000, // 8\n} as const;\n\n// Map string modifier names to bitwise flags for parsing\nexport type ModifierNames = {\n '⇧': number;\n shift: number;\n '⌥': number;\n alt: number;\n option: number;\n '⌃': number;\n ctrl: number;\n control: number;\n '⌘': number;\n cmd: number;\n command: number;\n};\n\nexport const MODIFIERS: ModifierNames = {\n '⇧': MODS.SHIFT,\n shift: MODS.SHIFT,\n '⌥': MODS.ALT,\n alt: MODS.ALT,\n option: MODS.ALT,\n '⌃': MODS.CTRL,\n ctrl: MODS.CTRL,\n control: MODS.CTRL,\n '⌘': MODS.META,\n cmd: MODS.META,\n command: MODS.META,\n};\n\n// Modern key mapping using KeyboardEvent.key values\nexport const SPECIAL: { [key: string]: string } = {\n backspace: 'Backspace',\n tab: 'Tab',\n clear: 'Clear',\n enter: 'Enter',\n return: 'Enter',\n esc: 'Escape',\n escape: 'Escape',\n space: ' ',\n left: 'ArrowLeft',\n up: 'ArrowUp',\n right: 'ArrowRight',\n down: 'ArrowDown',\n del: 'Delete',\n delete: 'Delete',\n home: 'Home',\n end: 'End',\n pageup: 'PageUp',\n pagedown: 'PageDown',\n comma: ',',\n '.': '.',\n '/': '/',\n '`': '`',\n '-': '-',\n '=': '=',\n ';': ';',\n \"'\": \"'\",\n '[': '[',\n ']': ']',\n '\\\\': '\\\\',\n // Normalize Meta key variants\n 'Meta': 'Meta',\n 'MetaLeft': 'Meta',\n 'MetaRight': 'Meta', \n 'OS': 'Meta', // Some browsers use OS instead of Meta\n 'ContextMenu': 'Meta', // Right-click context menu key sometimes acts as Meta\n // Add identity mappings for already-normalized keys\n 'ArrowLeft': 'ArrowLeft',\n 'ArrowUp': 'ArrowUp',\n 'ArrowRight': 'ArrowRight',\n 'ArrowDown': 'ArrowDown',\n 'Backspace': 'Backspace',\n 'Tab': 'Tab',\n 'Clear': 'Clear',\n 'Enter': 'Enter',\n 'Escape': 'Escape',\n 'Delete': 'Delete',\n 'Home': 'Home',\n 'End': 'End',\n 'PageUp': 'PageUp',\n 'PageDown': 'PageDown',\n};\n\nexport const CAPS_LOCK_KEY = 'CapsLock';\n","import { KeyString, MODS, SPECIAL } from '../constants';\n\nexport const getKeyIdentifier = (key: string): KeyString => {\n return (SPECIAL[key] || key.toUpperCase()) as KeyString;\n};\n\nexport const updateModifiers = (e: KeyboardEvent): number => {\n let modifiers = 0;\n if (e.shiftKey) modifiers |= MODS.SHIFT;\n if (e.altKey) modifiers |= MODS.ALT;\n if (e.ctrlKey) modifiers |= MODS.CTRL;\n if (e.metaKey) modifiers |= MODS.META;\n return modifiers;\n};\n","import { KeyString, MODIFIERS, ModifierNames, SPECIAL } from '../constants';\n\nexport interface ParsedShortcut {\n mods: number; // Bitwise flag for modifiers\n special: string[];\n}\nexport interface KeyMap {\n key: KeyString;\n shortcut: ParsedShortcut;\n}\n\nexport const getKeyIdentifier = (key: string): KeyString =>\n (SPECIAL[key] || key.toUpperCase()) as KeyString;\n\nconst getMods = (keys: string[]): ParsedShortcut =>\n keys.reduce(\n (acc, key) => {\n if (key in MODIFIERS) {\n acc.mods |= MODIFIERS[key as keyof ModifierNames];\n } else {\n acc.special.push(SPECIAL[key] || key.toUpperCase());\n }\n return acc;\n },\n {\n mods: 0, // Start with no modifiers\n special: [],\n } as ParsedShortcut,\n );\n\nconst getCombinations = (keysStr: string): string[] => {\n const cleanKeys = keysStr.replace(/\\s/g, '');\n const keys = cleanKeys.split(',');\n if (keys[keys.length - 1] === '') {\n keys[keys.length - 2] += ',';\n }\n\n return keys;\n};\n\nexport const getKeyMap = (keysStr: string): KeyMap[] => {\n const keymap = getCombinations(keysStr);\n return keymap.map((keyCmd) => {\n const keys = keyCmd.split('+');\n const key = keys[keys.length - 1];\n const keyIdentifier = getKeyIdentifier(key);\n\n return {\n key: keyIdentifier,\n shortcut: getMods(keys),\n };\n });\n};\n","export const invariant = (\n condition: boolean,\n message: string,\n ...args: unknown[]\n) => {\n if (\n typeof process !== 'undefined' &&\n process.env &&\n process.env.NODE_ENV === 'development' &&\n !condition\n ) {\n throw new Error(\n `Invariant failed: ${message}${args.length ? ` ${JSON.stringify(args)}` : ''}`,\n );\n }\n};\n\nexport const isFirefox = navigator.userAgent.includes('Firefox');\n\nexport const isEditable = (el: HTMLElement): boolean =>\n el.isContentEditable ||\n el.tagName === 'INPUT' ||\n el.tagName === 'SELECT' ||\n el.tagName === 'TEXTAREA';\n\nexport const isEqArray = (\n arr1: (string | number)[],\n arr2: (string | number)[],\n): boolean => {\n if (arr1.length !== arr2.length) return false;\n\n for (let i = 0; i < arr1.length; i++) {\n if (arr1[i] !== arr2[i]) return false;\n }\n\n return true;\n};\n","import { CAPS_LOCK_KEY, DEFAULT_SCOPE, KeyString } from './constants';\nimport { getKeyIdentifier, updateModifiers } from './helpers/keyboard';\nimport { getKeyMap, ParsedShortcut } from './helpers/keymap';\nimport { invariant, isEditable, isEqArray, isFirefox } from './helpers/utils';\n\ntype noop = (e: KeyboardEvent) => void;\ntype FilterFn = (el: KeyboardEvent) => boolean;\n\ninterface Handler {\n scope: string;\n method: noop;\n shortcut: ParsedShortcut;\n skipOther: boolean;\n}\n\nconst defaultFilter = (e: KeyboardEvent): boolean =>\n e && !isEditable(e.target as HTMLElement);\n\n// WeakMap to track event listener references per document to prevent memory leaks\nconst documentListeners = new WeakMap<\n Document,\n {\n dispatch: (e: KeyboardEvent) => void;\n cleanUp: (e: KeyboardEvent) => void;\n reset: () => void;\n }\n>();\n\nexport function createKeybuddy(\n doc: Document,\n filterFn: FilterFn = defaultFilter,\n) {\n let handlers: { [key: KeyString]: Handler[] } = {};\n const downKeys: Set<KeyString> = new Set();\n let activeScope = DEFAULT_SCOPE;\n\n let modifiers = 0; // Bitwise flag for active modifiers\n\n const bindKey = (\n keysStr: string,\n scopeOrMethod: string | noop,\n methodOrNull: noop = () => {},\n {\n skipOther,\n }: {\n skipOther: boolean;\n } = {\n skipOther: false,\n },\n ): void => {\n const scope: string =\n typeof scopeOrMethod === 'function' ? DEFAULT_SCOPE : scopeOrMethod;\n const method: noop =\n typeof scopeOrMethod === 'function' ? scopeOrMethod : methodOrNull;\n\n getKeyMap(keysStr).forEach(({ key, shortcut }) => {\n if (!handlers[key]) {\n handlers[key] = [];\n }\n const handler = handlers[key];\n if (process.env.NODE_ENV === 'development') {\n if (skipOther) {\n const action = handler.find((i) => i.skipOther);\n invariant(\n !action,\n \"Conflicting 'skipOther' property with action\",\n action,\n );\n }\n }\n\n handler.push({\n scope,\n method,\n shortcut,\n skipOther,\n });\n });\n };\n\n const unbindKeyProcess = (\n keysStr: string,\n deleteMethod: null | noop,\n deleteScope: string = DEFAULT_SCOPE,\n ): void => {\n getKeyMap(keysStr).forEach(({ key, shortcut }) => {\n const handler = handlers[key];\n if (Array.isArray(handler)) {\n const handler = handlers[key].filter(\n ({ scope, method, shortcut: methodShortcut }: Handler) =>\n !(\n scope === deleteScope &&\n methodShortcut.mods === shortcut.mods &&\n isEqArray(methodShortcut.special, shortcut.special) &&\n (deleteMethod === null ? true : method === deleteMethod)\n ),\n );\n if (handler.length) {\n handlers[key] = handler;\n } else {\n delete handlers[key];\n }\n }\n });\n };\n\n const unbindKey = (\n keysStr: string,\n scopeOrMethod: string | noop,\n methodOrNull: noop = () => {},\n ) => {\n const deleteScope: string =\n typeof scopeOrMethod === 'function' ? DEFAULT_SCOPE : scopeOrMethod;\n const deleteMethod: noop =\n typeof scopeOrMethod === 'function' ? scopeOrMethod : methodOrNull;\n return unbindKeyProcess(keysStr, deleteMethod, deleteScope);\n };\n\n const unsafeUnbindKey = (keysStr: string, scope?: string) =>\n unbindKeyProcess(keysStr, null, scope);\n\n const dispatch = (e: KeyboardEvent) => {\n const key = getKeyIdentifier(e.key);\n\n if (!filterFn(e)) {\n return;\n }\n\n // fix firefox behavior when caps lock fires three times onkeydown\n // and don't fire at all onkeyup (Firefox 72)\n if (isFirefox && key === CAPS_LOCK_KEY) {\n return;\n }\n\n modifiers = updateModifiers(e);\n\n // Check if key is not a modifier\n const isModifierKey =\n key === ('SHIFT' as KeyString) ||\n key === ('ALT' as KeyString) ||\n key === ('CTRL' as KeyString) ||\n key === ('META' as KeyString);\n if (!isModifierKey && !downKeys.has(key)) {\n downKeys.add(key);\n }\n // See if we need to ignore the keypress (filter() can can be overridden)\n // by default ignore key presses if a select, textarea, or input is focused\n // if (!assignKey.filter.call(this, event)) return;\n\n // abort if no potentially matching shortcuts found\n if (!(key in handlers)) {\n return;\n }\n\n const currentHandlers = handlers[key].filter(\n ({ scope, shortcut: { special, mods } }) => {\n if (scope !== activeScope) {\n return false;\n }\n\n return isEqArray(special, Array.from(downKeys)) && mods === modifiers;\n },\n );\n\n const primaryAction: Handler | undefined = currentHandlers.find(\n (action) => action.skipOther,\n );\n if (primaryAction) {\n primaryAction.method(e);\n } else {\n currentHandlers.forEach(({ method }) => {\n method(e);\n });\n }\n };\n\n const cleanUp = (e: KeyboardEvent) => {\n const key = getKeyIdentifier(e.key);\n\n // clean all for meta.\n // Main reason is ctrl+z (or any other native command not fires letter keyup on editable inputs)\n if (e.key && e.key.toLowerCase() === 'meta') {\n downKeys.clear();\n } else {\n downKeys.delete(key);\n }\n };\n\n const unbindScope = (deleteScope: string): void => {\n Object.keys(handlers).forEach((key) => {\n const keyString = key as KeyString;\n const handler = handlers[keyString].filter(\n ({ scope }: Handler) => scope !== deleteScope,\n );\n if (handler.length) {\n handlers[keyString] = handler;\n } else {\n delete handlers[keyString];\n }\n });\n };\n\n const setScope = (scope: string): void => {\n activeScope = scope;\n };\n\n const unbindAll = (): void => {\n handlers = {};\n downKeys.clear();\n };\n\n const reset = (): void => {\n downKeys.clear();\n };\n\n const destroy = (): void => {\n downKeys.clear();\n handlers = {};\n if (doc) {\n const listeners = documentListeners.get(doc);\n if (listeners) {\n doc.removeEventListener('keydown', listeners.dispatch);\n doc.removeEventListener('keyup', listeners.cleanUp);\n window.removeEventListener('focus', listeners.reset);\n documentListeners.delete(doc);\n }\n }\n };\n\n // Remove old listeners if they exist\n destroy();\n\n // Store and add new listeners\n documentListeners.set(doc, { dispatch, cleanUp, reset });\n doc.addEventListener('keydown', dispatch);\n doc.addEventListener('keyup', cleanUp);\n window.addEventListener('focus', reset);\n\n return {\n bind: bindKey,\n unbind: unbindKey,\n unsafeUnbind: unsafeUnbindKey,\n unbindScope,\n setScope,\n unbindAll,\n getScope: () => activeScope,\n destroy,\n };\n}\n"],"mappings":"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","names":["MODS","MODIFIERS","SPECIAL","CAPS_LOCK_KEY","getKeyIdentifier","key","SPECIAL","updateModifiers","modifiers","MODS","getKeyIdentifier","key","SPECIAL","getMods","keys","acc","MODIFIERS","getCombinations","keysStr","getKeyMap","keyCmd","isFirefox","isEditable","el","isEqArray","arr1","arr2","i","defaultFilter","isEditable","documentListeners","createKeybuddy","doc","filterFn","handlers","downKeys","activeScope","modifiers","bindKey","keysStr","scopeOrMethod","methodOrNull","skipOther","scope","method","getKeyMap","key","shortcut","unbindKeyProcess","deleteMethod","deleteScope","handler","methodShortcut","isEqArray","unbindKey","unsafeUnbindKey","dispatch","e","getKeyIdentifier","isFirefox","CAPS_LOCK_KEY","updateModifiers","currentHandlers","special","mods","primaryAction","action","cleanUp","unbindScope","keyString","setScope","unbindAll","reset","destroy","listeners"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "keybuddy",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "main": "./index.js",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -8,10 +8,6 @@
8
8
  "name": "Elvin Dzhavadov"
9
9
  },
10
10
  "repository": "https://github.com/elv1n/keybuddy",
11
- "dependencies": {
12
- "debug": "^4.1.1",
13
- "invariant": "^2.2.4"
14
- },
15
11
  "private": false,
16
12
  "typings": "./index.d.ts"
17
13
  }
@@ -1 +0,0 @@
1
- export {};
@@ -1,40 +0,0 @@
1
- "use strict";
2
-
3
- var _index = require("../index");
4
-
5
- describe('throwing error in development', () => {
6
- var {
7
- NODE_ENV
8
- } = process.env;
9
- beforeEach(() => {
10
- process.env.NODE_ENV = 'development';
11
- });
12
- afterEach(() => {
13
- process.env.NODE_ENV = NODE_ENV;
14
- (0, _index.unbindAll)();
15
- });
16
- it('should not throw error if skipOther single', () => {
17
- var fn = jest.fn();
18
- (0, _index.bindKey)('e', _index.DEFAULT_SCOPE, fn);
19
- expect(() => (0, _index.bindKey)('e', _index.DEFAULT_SCOPE, fn, {
20
- skipOther: true
21
- })).not.toThrow();
22
- });
23
- it('should not throw error if skipOther single', () => {
24
- var fn = jest.fn();
25
- (0, _index.bindKey)('e', _index.DEFAULT_SCOPE, fn, {
26
- skipOther: true
27
- });
28
- expect(() => (0, _index.bindKey)('e', _index.DEFAULT_SCOPE, fn)).not.toThrow();
29
- });
30
- it('should throw error on using skipOthers twice', () => {
31
- var fn = jest.fn();
32
- (0, _index.bindKey)('e', _index.DEFAULT_SCOPE, fn, {
33
- skipOther: true
34
- });
35
- expect(() => (0, _index.bindKey)('e', _index.DEFAULT_SCOPE, fn, {
36
- skipOther: true
37
- })).toThrow();
38
- });
39
- });
40
- //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9fX3Rlc3RfXy9pbmRleC5zcGVjLnRzIl0sIm5hbWVzIjpbImRlc2NyaWJlIiwiTk9ERV9FTlYiLCJwcm9jZXNzIiwiZW52IiwiYmVmb3JlRWFjaCIsImFmdGVyRWFjaCIsIml0IiwiZm4iLCJqZXN0IiwiREVGQVVMVF9TQ09QRSIsImV4cGVjdCIsInNraXBPdGhlciIsIm5vdCIsInRvVGhyb3ciXSwibWFwcGluZ3MiOiI7O0FBQUE7O0FBRUFBLFFBQVEsQ0FBQywrQkFBRCxFQUFrQyxNQUFNO0FBQzlDLE1BQU07QUFBRUMsSUFBQUE7QUFBRixNQUFlQyxPQUFPLENBQUNDLEdBQTdCO0FBQ0FDLEVBQUFBLFVBQVUsQ0FBQyxNQUFNO0FBQ2ZGLElBQUFBLE9BQU8sQ0FBQ0MsR0FBUixDQUFZRixRQUFaLEdBQXVCLGFBQXZCO0FBQ0QsR0FGUyxDQUFWO0FBR0FJLEVBQUFBLFNBQVMsQ0FBQyxNQUFNO0FBQ2RILElBQUFBLE9BQU8sQ0FBQ0MsR0FBUixDQUFZRixRQUFaLEdBQXVCQSxRQUF2QjtBQUNBO0FBQ0QsR0FIUSxDQUFUO0FBSUFLLEVBQUFBLEVBQUUsQ0FBQyw0Q0FBRCxFQUErQyxNQUFNO0FBQ3JELFFBQU1DLEVBQUUsR0FBR0MsSUFBSSxDQUFDRCxFQUFMLEVBQVg7QUFDQSx3QkFBUSxHQUFSLEVBQWFFLG9CQUFiLEVBQTRCRixFQUE1QjtBQUNBRyxJQUFBQSxNQUFNLENBQUMsTUFDTCxvQkFBUSxHQUFSLEVBQWFELG9CQUFiLEVBQTRCRixFQUE1QixFQUFnQztBQUFFSSxNQUFBQSxTQUFTLEVBQUU7QUFBYixLQUFoQyxDQURJLENBQU4sQ0FFRUMsR0FGRixDQUVNQyxPQUZOO0FBR0QsR0FOQyxDQUFGO0FBT0FQLEVBQUFBLEVBQUUsQ0FBQyw0Q0FBRCxFQUErQyxNQUFNO0FBQ3JELFFBQU1DLEVBQUUsR0FBR0MsSUFBSSxDQUFDRCxFQUFMLEVBQVg7QUFDQSx3QkFBUSxHQUFSLEVBQWFFLG9CQUFiLEVBQTRCRixFQUE1QixFQUFnQztBQUFFSSxNQUFBQSxTQUFTLEVBQUU7QUFBYixLQUFoQztBQUNBRCxJQUFBQSxNQUFNLENBQUMsTUFBTSxvQkFBUSxHQUFSLEVBQWFELG9CQUFiLEVBQTRCRixFQUE1QixDQUFQLENBQU4sQ0FBOENLLEdBQTlDLENBQWtEQyxPQUFsRDtBQUNELEdBSkMsQ0FBRjtBQUtBUCxFQUFBQSxFQUFFLENBQUMsOENBQUQsRUFBaUQsTUFBTTtBQUN2RCxRQUFNQyxFQUFFLEdBQUdDLElBQUksQ0FBQ0QsRUFBTCxFQUFYO0FBQ0Esd0JBQVEsR0FBUixFQUFhRSxvQkFBYixFQUE0QkYsRUFBNUIsRUFBZ0M7QUFBRUksTUFBQUEsU0FBUyxFQUFFO0FBQWIsS0FBaEM7QUFDQUQsSUFBQUEsTUFBTSxDQUFDLE1BQ0wsb0JBQVEsR0FBUixFQUFhRCxvQkFBYixFQUE0QkYsRUFBNUIsRUFBZ0M7QUFBRUksTUFBQUEsU0FBUyxFQUFFO0FBQWIsS0FBaEMsQ0FESSxDQUFOLENBRUVFLE9BRkY7QUFHRCxHQU5DLENBQUY7QUFPRCxDQTVCTyxDQUFSIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgYmluZEtleSwgdW5iaW5kQWxsLCBERUZBVUxUX1NDT1BFIH0gZnJvbSAnLi4vaW5kZXgnO1xuXG5kZXNjcmliZSgndGhyb3dpbmcgZXJyb3IgaW4gZGV2ZWxvcG1lbnQnLCAoKSA9PiB7XG4gIGNvbnN0IHsgTk9ERV9FTlYgfSA9IHByb2Nlc3MuZW52O1xuICBiZWZvcmVFYWNoKCgpID0+IHtcbiAgICBwcm9jZXNzLmVudi5OT0RFX0VOViA9ICdkZXZlbG9wbWVudCc7XG4gIH0pO1xuICBhZnRlckVhY2goKCkgPT4ge1xuICAgIHByb2Nlc3MuZW52Lk5PREVfRU5WID0gTk9ERV9FTlY7XG4gICAgdW5iaW5kQWxsKCk7XG4gIH0pO1xuICBpdCgnc2hvdWxkIG5vdCB0aHJvdyBlcnJvciBpZiBza2lwT3RoZXIgc2luZ2xlJywgKCkgPT4ge1xuICAgIGNvbnN0IGZuID0gamVzdC5mbigpO1xuICAgIGJpbmRLZXkoJ2UnLCBERUZBVUxUX1NDT1BFLCBmbik7XG4gICAgZXhwZWN0KCgpID0+XG4gICAgICBiaW5kS2V5KCdlJywgREVGQVVMVF9TQ09QRSwgZm4sIHsgc2tpcE90aGVyOiB0cnVlIH0pXG4gICAgKS5ub3QudG9UaHJvdygpO1xuICB9KTtcbiAgaXQoJ3Nob3VsZCBub3QgdGhyb3cgZXJyb3IgaWYgc2tpcE90aGVyIHNpbmdsZScsICgpID0+IHtcbiAgICBjb25zdCBmbiA9IGplc3QuZm4oKTtcbiAgICBiaW5kS2V5KCdlJywgREVGQVVMVF9TQ09QRSwgZm4sIHsgc2tpcE90aGVyOiB0cnVlIH0pO1xuICAgIGV4cGVjdCgoKSA9PiBiaW5kS2V5KCdlJywgREVGQVVMVF9TQ09QRSwgZm4pKS5ub3QudG9UaHJvdygpO1xuICB9KTtcbiAgaXQoJ3Nob3VsZCB0aHJvdyBlcnJvciBvbiB1c2luZyBza2lwT3RoZXJzIHR3aWNlJywgKCkgPT4ge1xuICAgIGNvbnN0IGZuID0gamVzdC5mbigpO1xuICAgIGJpbmRLZXkoJ2UnLCBERUZBVUxUX1NDT1BFLCBmbiwgeyBza2lwT3RoZXI6IHRydWUgfSk7XG4gICAgZXhwZWN0KCgpID0+XG4gICAgICBiaW5kS2V5KCdlJywgREVGQVVMVF9TQ09QRSwgZm4sIHsgc2tpcE90aGVyOiB0cnVlIH0pXG4gICAgKS50b1Rocm93KCk7XG4gIH0pO1xufSk7XG4iXX0=
package/constants.d.ts DELETED
@@ -1,26 +0,0 @@
1
- export declare const DEFAULT_SCOPE = "all";
2
- declare type ValueOf<T> = T[keyof T];
3
- export declare type Modifiers = {
4
- '⇧': 16;
5
- shift: 16;
6
- '⌥': 18;
7
- alt: 18;
8
- option: 18;
9
- '⌃': 17;
10
- ctrl: 17;
11
- control: 17;
12
- '⌘': 91;
13
- command: 91;
14
- };
15
- export declare const MODIFIERS: Modifiers;
16
- export declare type ModifierMap = {
17
- [key in ValueOf<Modifiers>]: 'shiftKey' | 'altKey' | 'ctrlKey' | 'metaKey';
18
- };
19
- export declare type ModifierKeys = Array<keyof ModifierMap>;
20
- export declare const MODIFIERS_MAP: ModifierMap;
21
- export declare const MODIFIERS_KEYS: ModifierKeys;
22
- export declare const SPECIAL: {
23
- [key: string]: number;
24
- };
25
- export declare const CAPS_LOCK = 20;
26
- export {};
package/constants.js DELETED
@@ -1,69 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.CAPS_LOCK = exports.SPECIAL = exports.MODIFIERS_KEYS = exports.MODIFIERS_MAP = exports.MODIFIERS = exports.DEFAULT_SCOPE = void 0;
7
-
8
- var _browser = require("./helpers/browser");
9
-
10
- var DEFAULT_SCOPE = 'all';
11
- exports.DEFAULT_SCOPE = DEFAULT_SCOPE;
12
- var MODIFIERS = {
13
- '⇧': 16,
14
- shift: 16,
15
- '⌥': 18,
16
- alt: 18,
17
- option: 18,
18
- '⌃': 17,
19
- ctrl: 17,
20
- control: 17,
21
- '⌘': 91,
22
- command: 91
23
- };
24
- exports.MODIFIERS = MODIFIERS;
25
- var MODIFIERS_MAP = {
26
- [MODIFIERS.shift]: 'shiftKey',
27
- [MODIFIERS.alt]: 'altKey',
28
- [MODIFIERS.ctrl]: 'ctrlKey',
29
- [MODIFIERS.command]: 'metaKey'
30
- };
31
- exports.MODIFIERS_MAP = MODIFIERS_MAP;
32
- var MODIFIERS_KEYS = Object.keys(MODIFIERS_MAP).map(i => Number(i)); // Special keys
33
-
34
- exports.MODIFIERS_KEYS = MODIFIERS_KEYS;
35
- var SPECIAL = {
36
- backspace: 8,
37
- tab: 9,
38
- clear: 12,
39
- enter: 13,
40
- return: 13,
41
- esc: 27,
42
- escape: 27,
43
- space: 32,
44
- left: 37,
45
- up: 38,
46
- right: 39,
47
- down: 40,
48
- del: 46,
49
- delete: 46,
50
- home: 36,
51
- end: 35,
52
- pageup: 33,
53
- pagedown: 34,
54
- comma: 188,
55
- '.': 190,
56
- '/': 191,
57
- '`': 192,
58
- '-': _browser.isFirefox ? 173 : 189,
59
- '=': _browser.isFirefox ? 61 : 187,
60
- ';': 186,
61
- "'": 222,
62
- '[': 219,
63
- ']': 221,
64
- '\\': 220
65
- };
66
- exports.SPECIAL = SPECIAL;
67
- var CAPS_LOCK = 20;
68
- exports.CAPS_LOCK = CAPS_LOCK;
69
- //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NyYy9jb25zdGFudHMudHMiXSwibmFtZXMiOlsiREVGQVVMVF9TQ09QRSIsIk1PRElGSUVSUyIsInNoaWZ0IiwiYWx0Iiwib3B0aW9uIiwiY3RybCIsImNvbnRyb2wiLCJjb21tYW5kIiwiTU9ESUZJRVJTX01BUCIsIk1PRElGSUVSU19LRVlTIiwiT2JqZWN0Iiwia2V5cyIsIm1hcCIsImkiLCJOdW1iZXIiLCJTUEVDSUFMIiwiYmFja3NwYWNlIiwidGFiIiwiY2xlYXIiLCJlbnRlciIsInJldHVybiIsImVzYyIsImVzY2FwZSIsInNwYWNlIiwibGVmdCIsInVwIiwicmlnaHQiLCJkb3duIiwiZGVsIiwiZGVsZXRlIiwiaG9tZSIsImVuZCIsInBhZ2V1cCIsInBhZ2Vkb3duIiwiY29tbWEiLCJpc0ZpcmVmb3giLCJDQVBTX0xPQ0siXSwibWFwcGluZ3MiOiI7Ozs7Ozs7QUFBQTs7QUFFTyxJQUFNQSxhQUFhLEdBQUcsS0FBdEI7O0FBZ0JBLElBQU1DLFNBQW9CLEdBQUc7QUFDbEMsT0FBSyxFQUQ2QjtBQUVsQ0MsRUFBQUEsS0FBSyxFQUFFLEVBRjJCO0FBR2xDLE9BQUssRUFINkI7QUFJbENDLEVBQUFBLEdBQUcsRUFBRSxFQUo2QjtBQUtsQ0MsRUFBQUEsTUFBTSxFQUFFLEVBTDBCO0FBTWxDLE9BQUssRUFONkI7QUFPbENDLEVBQUFBLElBQUksRUFBRSxFQVA0QjtBQVFsQ0MsRUFBQUEsT0FBTyxFQUFFLEVBUnlCO0FBU2xDLE9BQUssRUFUNkI7QUFVbENDLEVBQUFBLE9BQU8sRUFBRTtBQVZ5QixDQUE3Qjs7QUF5QkEsSUFBTUMsYUFBMEIsR0FBRztBQUN4QyxHQUFDUCxTQUFTLENBQUNDLEtBQVgsR0FBbUIsVUFEcUI7QUFFeEMsR0FBQ0QsU0FBUyxDQUFDRSxHQUFYLEdBQWlCLFFBRnVCO0FBR3hDLEdBQUNGLFNBQVMsQ0FBQ0ksSUFBWCxHQUFrQixTQUhzQjtBQUl4QyxHQUFDSixTQUFTLENBQUNNLE9BQVgsR0FBcUI7QUFKbUIsQ0FBbkM7O0FBT0EsSUFBTUUsY0FBYyxHQUFHQyxNQUFNLENBQUNDLElBQVAsQ0FBWUgsYUFBWixFQUEyQkksR0FBM0IsQ0FBK0JDLENBQUMsSUFDNURDLE1BQU0sQ0FBQ0QsQ0FBRCxDQURzQixDQUF2QixDLENBSVA7OztBQUNPLElBQU1FLE9BQWtDLEdBQUc7QUFDaERDLEVBQUFBLFNBQVMsRUFBRSxDQURxQztBQUVoREMsRUFBQUEsR0FBRyxFQUFFLENBRjJDO0FBR2hEQyxFQUFBQSxLQUFLLEVBQUUsRUFIeUM7QUFJaERDLEVBQUFBLEtBQUssRUFBRSxFQUp5QztBQUtoREMsRUFBQUEsTUFBTSxFQUFFLEVBTHdDO0FBTWhEQyxFQUFBQSxHQUFHLEVBQUUsRUFOMkM7QUFPaERDLEVBQUFBLE1BQU0sRUFBRSxFQVB3QztBQVFoREMsRUFBQUEsS0FBSyxFQUFFLEVBUnlDO0FBU2hEQyxFQUFBQSxJQUFJLEVBQUUsRUFUMEM7QUFVaERDLEVBQUFBLEVBQUUsRUFBRSxFQVY0QztBQVdoREMsRUFBQUEsS0FBSyxFQUFFLEVBWHlDO0FBWWhEQyxFQUFBQSxJQUFJLEVBQUUsRUFaMEM7QUFhaERDLEVBQUFBLEdBQUcsRUFBRSxFQWIyQztBQWNoREMsRUFBQUEsTUFBTSxFQUFFLEVBZHdDO0FBZWhEQyxFQUFBQSxJQUFJLEVBQUUsRUFmMEM7QUFnQmhEQyxFQUFBQSxHQUFHLEVBQUUsRUFoQjJDO0FBaUJoREMsRUFBQUEsTUFBTSxFQUFFLEVBakJ3QztBQWtCaERDLEVBQUFBLFFBQVEsRUFBRSxFQWxCc0M7QUFtQmhEQyxFQUFBQSxLQUFLLEVBQUUsR0FuQnlDO0FBb0JoRCxPQUFLLEdBcEIyQztBQXFCaEQsT0FBSyxHQXJCMkM7QUFzQmhELE9BQUssR0F0QjJDO0FBdUJoRCxPQUFLQyxxQkFBWSxHQUFaLEdBQWtCLEdBdkJ5QjtBQXdCaEQsT0FBS0EscUJBQVksRUFBWixHQUFpQixHQXhCMEI7QUF5QmhELE9BQUssR0F6QjJDO0FBMEJoRCxPQUFLLEdBMUIyQztBQTJCaEQsT0FBSyxHQTNCMkM7QUE0QmhELE9BQUssR0E1QjJDO0FBNkJoRCxRQUFNO0FBN0IwQyxDQUEzQzs7QUErQkEsSUFBTUMsU0FBUyxHQUFHLEVBQWxCIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgaXNGaXJlZm94IH0gZnJvbSAnLi9oZWxwZXJzL2Jyb3dzZXInO1xuXG5leHBvcnQgY29uc3QgREVGQVVMVF9TQ09QRSA9ICdhbGwnO1xuXG50eXBlIFZhbHVlT2Y8VD4gPSBUW2tleW9mIFRdO1xuXG5leHBvcnQgdHlwZSBNb2RpZmllcnMgPSB7XG4gICfih6cnOiAxNjtcbiAgc2hpZnQ6IDE2O1xuICAn4oylJzogMTg7XG4gIGFsdDogMTg7XG4gIG9wdGlvbjogMTg7XG4gICfijIMnOiAxNztcbiAgY3RybDogMTc7XG4gIGNvbnRyb2w6IDE3O1xuICAn4oyYJzogOTE7XG4gIGNvbW1hbmQ6IDkxO1xufTtcbmV4cG9ydCBjb25zdCBNT0RJRklFUlM6IE1vZGlmaWVycyA9IHtcbiAgJ+KHpyc6IDE2LFxuICBzaGlmdDogMTYsXG4gICfijKUnOiAxOCxcbiAgYWx0OiAxOCxcbiAgb3B0aW9uOiAxOCxcbiAgJ+KMgyc6IDE3LFxuICBjdHJsOiAxNyxcbiAgY29udHJvbDogMTcsXG4gICfijJgnOiA5MSxcbiAgY29tbWFuZDogOTFcbn07XG5cbmV4cG9ydCB0eXBlIE1vZGlmaWVyTWFwID0ge1xuICBba2V5IGluIFZhbHVlT2Y8TW9kaWZpZXJzPl06ICdzaGlmdEtleScgfCAnYWx0S2V5JyB8ICdjdHJsS2V5JyB8ICdtZXRhS2V5Jztcbn07XG4vLyBleHBvcnQgdHlwZSBNb2RpZmllck1hcCA9IHtcbi8vICAgMTY6ICdzaGlmdEtleSc7XG4vLyAgIDE4OiAnYWx0S2V5Jztcbi8vICAgMTc6ICdjdHJsS2V5Jztcbi8vICAgOTE6ICdtZXRhS2V5Jztcbi8vIH07XG5cbmV4cG9ydCB0eXBlIE1vZGlmaWVyS2V5cyA9IEFycmF5PGtleW9mIE1vZGlmaWVyTWFwPjtcblxuZXhwb3J0IGNvbnN0IE1PRElGSUVSU19NQVA6IE1vZGlmaWVyTWFwID0ge1xuICBbTU9ESUZJRVJTLnNoaWZ0XTogJ3NoaWZ0S2V5JyxcbiAgW01PRElGSUVSUy5hbHRdOiAnYWx0S2V5JyxcbiAgW01PRElGSUVSUy5jdHJsXTogJ2N0cmxLZXknLFxuICBbTU9ESUZJRVJTLmNvbW1hbmRdOiAnbWV0YUtleSdcbn07XG5cbmV4cG9ydCBjb25zdCBNT0RJRklFUlNfS0VZUyA9IE9iamVjdC5rZXlzKE1PRElGSUVSU19NQVApLm1hcChpID0+XG4gIE51bWJlcihpKVxuKSBhcyBNb2RpZmllcktleXM7XG5cbi8vIFNwZWNpYWwga2V5c1xuZXhwb3J0IGNvbnN0IFNQRUNJQUw6IHsgW2tleTogc3RyaW5nXTogbnVtYmVyIH0gPSB7XG4gIGJhY2tzcGFjZTogOCxcbiAgdGFiOiA5LFxuICBjbGVhcjogMTIsXG4gIGVudGVyOiAxMyxcbiAgcmV0dXJuOiAxMyxcbiAgZXNjOiAyNyxcbiAgZXNjYXBlOiAyNyxcbiAgc3BhY2U6IDMyLFxuICBsZWZ0OiAzNyxcbiAgdXA6IDM4LFxuICByaWdodDogMzksXG4gIGRvd246IDQwLFxuICBkZWw6IDQ2LFxuICBkZWxldGU6IDQ2LFxuICBob21lOiAzNixcbiAgZW5kOiAzNSxcbiAgcGFnZXVwOiAzMyxcbiAgcGFnZWRvd246IDM0LFxuICBjb21tYTogMTg4LFxuICAnLic6IDE5MCxcbiAgJy8nOiAxOTEsXG4gICdgJzogMTkyLFxuICAnLSc6IGlzRmlyZWZveCA/IDE3MyA6IDE4OSxcbiAgJz0nOiBpc0ZpcmVmb3ggPyA2MSA6IDE4NyxcbiAgJzsnOiAxODYsXG4gIFwiJ1wiOiAyMjIsXG4gICdbJzogMjE5LFxuICAnXSc6IDIyMSxcbiAgJ1xcXFwnOiAyMjBcbn07XG5leHBvcnQgY29uc3QgQ0FQU19MT0NLID0gMjA7XG4iXX0=
package/creator.js DELETED
@@ -1,273 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.default = void 0;
7
-
8
- var _invariant = _interopRequireDefault(require("invariant"));
9
-
10
- var _debug = _interopRequireDefault(require("debug"));
11
-
12
- var _constants = require("./constants");
13
-
14
- var _keymap = require("./helpers/keymap");
15
-
16
- var _data = require("./helpers/data");
17
-
18
- var _browser = require("./helpers/browser");
19
-
20
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
21
-
22
- var log = (0, _debug.default)('keybuddy');
23
-
24
- var defaultFilter = e => e && !(0, _browser.isEditable)(e.target);
25
-
26
- var _default = function _default(doc) {
27
- var filterFn = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : defaultFilter;
28
- var handlers = {};
29
- var downKeys = [];
30
- var activeScope = _constants.DEFAULT_SCOPE;
31
-
32
- var modifiers = _constants.MODIFIERS_KEYS.reduce((acc, key) => {
33
- acc[key] = false;
34
- return acc;
35
- }, {});
36
-
37
- var modsKeys = Object.keys(modifiers).map(i => Number(i));
38
-
39
- var updateModifiers = e => {
40
- modsKeys.forEach(key => {
41
- modifiers[key] = e[_constants.MODIFIERS_MAP[key]];
42
- });
43
- log('Update modifiers', modifiers);
44
- };
45
-
46
- var bindKey = function bindKey(keysStr, scopeOrMethod) {
47
- var methodOrNull = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : () => {};
48
- var {
49
- skipOther
50
- } = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {
51
- skipOther: false
52
- };
53
- var scope = typeof scopeOrMethod === 'function' ? _constants.DEFAULT_SCOPE : scopeOrMethod;
54
- var method = typeof scopeOrMethod === 'function' ? scopeOrMethod : methodOrNull;
55
- (0, _keymap.getKeyMap)(keysStr).forEach((_ref) => {
56
- var {
57
- code,
58
- shortcut
59
- } = _ref;
60
-
61
- if (!handlers[code]) {
62
- handlers[code] = [];
63
- }
64
-
65
- var handler = handlers[code];
66
-
67
- if (process.env.NODE_ENV === 'development') {
68
- if (skipOther) {
69
- var action = handler.find(i => i.skipOther);
70
- (0, _invariant.default)(!action, "Conflicting 'skipOther' property with action", action);
71
- }
72
- }
73
-
74
- handler.push({
75
- scope,
76
- method,
77
- shortcut,
78
- skipOther
79
- });
80
- });
81
- };
82
-
83
- var unbindKeyProcess = function unbindKeyProcess(keysStr, deleteMethod) {
84
- var deleteScope = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : _constants.DEFAULT_SCOPE;
85
- (0, _keymap.getKeyMap)(keysStr).forEach((_ref2) => {
86
- var {
87
- code,
88
- shortcut
89
- } = _ref2;
90
- var handler = handlers[code];
91
-
92
- if (Array.isArray(handler)) {
93
- var _handler = handlers[code].filter((_ref3) => {
94
- var {
95
- scope,
96
- method,
97
- shortcut: methodShortcut
98
- } = _ref3;
99
- return !(scope === deleteScope && (0, _data.isEqArray)(methodShortcut.mods, shortcut.mods) && (0, _data.isEqArray)(methodShortcut.special, shortcut.special) && (deleteMethod === null ? true : method === deleteMethod));
100
- });
101
-
102
- if (_handler.length) {
103
- handlers[code] = _handler;
104
- } else {
105
- delete handlers[code];
106
- }
107
- }
108
- });
109
- };
110
-
111
- var unbindKey = function unbindKey(keysStr, scopeOrMethod) {
112
- var methodOrNull = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : () => {};
113
- var deleteScope = typeof scopeOrMethod === 'function' ? _constants.DEFAULT_SCOPE : scopeOrMethod;
114
- var deleteMethod = typeof scopeOrMethod === 'function' ? scopeOrMethod : methodOrNull;
115
- return unbindKeyProcess(keysStr, deleteMethod, deleteScope);
116
- };
117
-
118
- var unsafeUnbindKey = (keysStr, scope) => unbindKeyProcess(keysStr, null, scope);
119
-
120
- var fixedKey = keyCode => {
121
- if (keyCode === 93 || keyCode === 224) {
122
- return 91;
123
- }
124
-
125
- return keyCode;
126
- };
127
-
128
- var dispatch = e => {
129
- var {
130
- keyCode
131
- } = e;
132
- var key = fixedKey(keyCode);
133
- log("Key ".concat(key));
134
-
135
- if (!filterFn(e)) {
136
- log('Filtered', filterFn);
137
- return;
138
- } // fix firefox behavior when caps lock fires three times onkeydown
139
- // and don't fire at all onkeyup (Firefox 72)
140
-
141
-
142
- if (_browser.isFirefox && key === _constants.CAPS_LOCK) {
143
- return;
144
- }
145
-
146
- updateModifiers(e);
147
-
148
- if (!{}.hasOwnProperty.call(modifiers, key) && !downKeys.includes(key)) {
149
- downKeys.push(key);
150
- log('Push down keys', downKeys);
151
- } // See if we need to ignore the keypress (filter() can can be overridden)
152
- // by default ignore key presses if a select, textarea, or input is focused
153
- // if (!assignKey.filter.call(this, event)) return;
154
- // abort if no potentially matching shortcuts found
155
-
156
-
157
- if (!(key in handlers)) {
158
- log('Key not in handler');
159
- return;
160
- }
161
-
162
- var currentHandlers = handlers[key].filter((_ref4) => {
163
- var {
164
- scope,
165
- shortcut: {
166
- special,
167
- mods
168
- }
169
- } = _ref4;
170
-
171
- if (scope !== activeScope) {
172
- return false;
173
- }
174
-
175
- return (0, _data.isEqArray)(special, downKeys) && (0, _data.isBoolArrayToObject)(mods, modifiers);
176
- });
177
- log('Handlers for', {
178
- key,
179
- downKeys,
180
- modifiers
181
- }, currentHandlers, handlers);
182
- var primaryAction = currentHandlers.find(action => action.skipOther);
183
-
184
- if (primaryAction) {
185
- primaryAction.method(e);
186
- } else {
187
- currentHandlers.forEach((_ref5) => {
188
- var {
189
- method
190
- } = _ref5;
191
- method(e);
192
- });
193
- }
194
- };
195
-
196
- var cleanUp = e => {
197
- var {
198
- keyCode
199
- } = e;
200
- var key = fixedKey(keyCode); // clean all for meta.
201
- // Main reason is ctrl+z (or any other native command not fires letter keyup on editable inputs)
202
-
203
- if (e.key && e.key.toLowerCase() === 'meta') {
204
- downKeys = [];
205
- } else {
206
- downKeys = downKeys.filter(i => i !== key);
207
- }
208
-
209
- log("Cleanup for ".concat(key), downKeys);
210
- };
211
-
212
- var unbindScope = deleteScope => {
213
- Object.keys(handlers).forEach(keyCode => {
214
- var handler = handlers[keyCode].filter((_ref6) => {
215
- var {
216
- scope
217
- } = _ref6;
218
- return scope !== deleteScope;
219
- });
220
-
221
- if (handler.length) {
222
- handlers[keyCode] = handler;
223
- } else {
224
- delete handlers[keyCode];
225
- }
226
- });
227
- };
228
-
229
- var setScope = scope => {
230
- activeScope = scope;
231
- };
232
-
233
- var unbindAll = () => {
234
- handlers = {};
235
- };
236
-
237
- var reset = () => {
238
- downKeys = [];
239
- };
240
-
241
- var destroy = () => {
242
- downKeys = [];
243
- handlers = {};
244
-
245
- if (doc) {
246
- doc.removeEventListener('keydown', dispatch);
247
- doc.removeEventListener('keyup', cleanUp); // Reset all on window focus
248
-
249
- window.removeEventListener('focus', reset);
250
- }
251
- };
252
-
253
- if (doc) {
254
- doc.addEventListener('keydown', dispatch);
255
- doc.addEventListener('keyup', cleanUp); // Reset all on window focus
256
-
257
- window.addEventListener('focus', reset);
258
- }
259
-
260
- return {
261
- bind: bindKey,
262
- unbind: unbindKey,
263
- unsafeUnbind: unsafeUnbindKey,
264
- unbindScope,
265
- setScope,
266
- unbindAll,
267
- getScope: () => activeScope,
268
- destroy
269
- };
270
- };
271
-
272
- exports.default = _default;
273
- //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uL3NyYy9jcmVhdG9yLnRzIl0sIm5hbWVzIjpbImxvZyIsImRlZmF1bHRGaWx0ZXIiLCJlIiwidGFyZ2V0IiwiZG9jIiwiZmlsdGVyRm4iLCJoYW5kbGVycyIsImRvd25LZXlzIiwiYWN0aXZlU2NvcGUiLCJERUZBVUxUX1NDT1BFIiwibW9kaWZpZXJzIiwiTU9ESUZJRVJTX0tFWVMiLCJyZWR1Y2UiLCJhY2MiLCJrZXkiLCJtb2RzS2V5cyIsIk9iamVjdCIsImtleXMiLCJtYXAiLCJpIiwiTnVtYmVyIiwidXBkYXRlTW9kaWZpZXJzIiwiZm9yRWFjaCIsIk1PRElGSUVSU19NQVAiLCJiaW5kS2V5Iiwia2V5c1N0ciIsInNjb3BlT3JNZXRob2QiLCJtZXRob2RPck51bGwiLCJza2lwT3RoZXIiLCJzY29wZSIsIm1ldGhvZCIsImNvZGUiLCJzaG9ydGN1dCIsImhhbmRsZXIiLCJwcm9jZXNzIiwiZW52IiwiTk9ERV9FTlYiLCJhY3Rpb24iLCJmaW5kIiwicHVzaCIsInVuYmluZEtleVByb2Nlc3MiLCJkZWxldGVNZXRob2QiLCJkZWxldGVTY29wZSIsIkFycmF5IiwiaXNBcnJheSIsImZpbHRlciIsIm1ldGhvZFNob3J0Y3V0IiwibW9kcyIsInNwZWNpYWwiLCJsZW5ndGgiLCJ1bmJpbmRLZXkiLCJ1bnNhZmVVbmJpbmRLZXkiLCJmaXhlZEtleSIsImtleUNvZGUiLCJkaXNwYXRjaCIsImlzRmlyZWZveCIsIkNBUFNfTE9DSyIsImhhc093blByb3BlcnR5IiwiY2FsbCIsImluY2x1ZGVzIiwiY3VycmVudEhhbmRsZXJzIiwicHJpbWFyeUFjdGlvbiIsImNsZWFuVXAiLCJ0b0xvd2VyQ2FzZSIsInVuYmluZFNjb3BlIiwic2V0U2NvcGUiLCJ1bmJpbmRBbGwiLCJyZXNldCIsImRlc3Ryb3kiLCJyZW1vdmVFdmVudExpc3RlbmVyIiwid2luZG93IiwiYWRkRXZlbnRMaXN0ZW5lciIsImJpbmQiLCJ1bmJpbmQiLCJ1bnNhZmVVbmJpbmQiLCJnZXRTY29wZSJd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Y2VzQ29udGVudCI6WyJpbXBvcnQgaW52YXJpYW50IGZyb20gJ2ludmFyaWFudCc7XG5pbXBvcnQgZGVidWcgZnJvbSAnZGVidWcnO1xuaW1wb3J0IHtcbiAgREVGQVVMVF9TQ09QRSxcbiAgTU9ESUZJRVJTX0tFWVMsXG4gIE1PRElGSUVSU19NQVAsXG4gIE1vZGlmaWVyTWFwLFxuICBNb2RpZmllcktleXMsXG4gIENBUFNfTE9DS1xufSBmcm9tICcuL2NvbnN0YW50cyc7XG5pbXBvcnQgeyBnZXRLZXlNYXAsIFBhcnNlZFNob3J0Y3V0IH0gZnJvbSAnLi9oZWxwZXJzL2tleW1hcCc7XG5pbXBvcnQgeyBpc0VxQXJyYXksIGlzQm9vbEFycmF5VG9PYmplY3QgfSBmcm9tICcuL2hlbHBlcnMvZGF0YSc7XG5pbXBvcnQgeyBpc0VkaXRhYmxlLCBpc0ZpcmVmb3ggfSBmcm9tICcuL2hlbHBlcnMvYnJvd3Nlcic7XG5cbnR5cGUgbm9vcCA9IChlOiBLZXlib2FyZEV2ZW50KSA9PiB2b2lkO1xudHlwZSBGaWx0ZXJGbiA9IChlbDogS2V5Ym9hcmRFdmVudCkgPT4gYm9vbGVhbjtcblxuaW50ZXJmYWNlIEhhbmRsZXIge1xuICBzY29wZTogc3RyaW5nO1xuICBtZXRob2Q6IG5vb3A7XG4gIHNob3J0Y3V0OiBQYXJzZWRTaG9ydGN1dDtcbiAgc2tpcE90aGVyOiBib29sZWFuO1xufVxuXG5jb25zdCBsb2cgPSBkZWJ1Zygna2V5YnVkZHknKTtcblxuY29uc3QgZGVmYXVsdEZpbHRlciA9IChlOiBLZXlib2FyZEV2ZW50KTogYm9vbGVhbiA9PlxuICBlICYmICFpc0VkaXRhYmxlKGUudGFyZ2V0IGFzIEhUTUxFbGVtZW50KTtcblxudHlwZSBNb2RzID0ge1xuICBba2V5IGluIGtleW9mIE1vZGlmaWVyTWFwXTogYm9vbGVhbjtcbn07XG5cbmV4cG9ydCBkZWZhdWx0IChkb2M/OiBIVE1MRG9jdW1lbnQsIGZpbHRlckZuOiBGaWx0ZXJGbiA9IGRlZmF1bHRGaWx0ZXIpID0+IHtcbiAgbGV0IGhhbmRsZXJzOiB7IFtrZXk6IHN0cmluZ106IEhhbmRsZXJbXSB9ID0ge307XG4gIGxldCBkb3duS2V5czogbnVtYmVyW10gPSBbXTtcbiAgbGV0IGFjdGl2ZVNjb3BlID0gREVGQVVMVF9TQ09QRTtcblxuICBjb25zdCBtb2RpZmllcnM6IE1vZHMgPSBNT0RJRklFUlNfS0VZUy5yZWR1Y2UoKGFjYywga2V5KSA9PiB7XG4gICAgYWNjW2tleV0gPSBmYWxzZTtcbiAgICByZXR1cm4gYWNjO1xuICB9LCB7fSBhcyBNb2RzKTtcbiAgY29uc3QgbW9kc0tleXMgPSBPYmplY3Qua2V5cyhtb2RpZmllcnMpLm1hcChpID0+IE51bWJlcihpKSkgYXMgTW9kaWZpZXJLZXlzO1xuXG4gIGNvbnN0IHVwZGF0ZU1vZGlmaWVycyA9IChlOiBLZXlib2FyZEV2ZW50KTogdm9pZCA9PiB7XG4gICAgbW9kc0tleXMuZm9yRWFjaChrZXkgPT4ge1xuICAgICAgbW9kaWZpZXJzW2tleV0gPSBlW01PRElGSUVSU19NQVBba2V5XV07XG4gICAgfSk7XG4gICAgbG9nKCdVcGRhdGUgbW9kaWZpZXJzJywgbW9kaWZpZXJzKTtcbiAgfTtcblxuICBjb25zdCBiaW5kS2V5ID0gKFxuICAgIGtleXNTdHI6IHN0cmluZyxcbiAgICBzY29wZU9yTWV0aG9kOiBzdHJpbmcgfCBub29wLFxuICAgIG1ldGhvZE9yTnVsbDogbm9vcCA9ICgpID0+IHt9LFxuICAgIHtcbiAgICAgIHNraXBPdGhlclxuICAgIH06IHtcbiAgICAgIHNraXBPdGhlcjogYm9vbGVhbjtcbiAgICB9ID0ge1xuICAgICAgc2tpcE90aGVyOiBmYWxzZVxuICAgIH1cbiAgKTogdm9pZCA9PiB7XG4gICAgY29uc3Qgc2NvcGU6IHN0cmluZyA9XG4gICAgICB0eXBlb2Ygc2NvcGVPck1ldGhvZCA9PT0gJ2Z1bmN0aW9uJyA/IERFRkFVTFRfU0NPUEUgOiBzY29wZU9yTWV0aG9kO1xuICAgIGNvbnN0IG1ldGhvZDogbm9vcCA9XG4gICAgICB0eXBlb2Ygc2NvcGVPck1ldGhvZCA9PT0gJ2Z1bmN0aW9uJyA/IHNjb3BlT3JNZXRob2QgOiBtZXRob2RPck51bGw7XG5cbiAgICBnZXRLZXlNYXAoa2V5c1N0cikuZm9yRWFjaCgoeyBjb2RlLCBzaG9ydGN1dCB9KSA9PiB7XG4gICAgICBpZiAoIWhhbmRsZXJzW2NvZGVdKSB7XG4gICAgICAgIGhhbmRsZXJzW2NvZGVdID0gW107XG4gICAgICB9XG4gICAgICBjb25zdCBoYW5kbGVyID0gaGFuZGxlcnNbY29kZV07XG4gICAgICBpZiAocHJvY2Vzcy5lbnYuTk9ERV9FTlYgPT09ICdkZXZlbG9wbWVudCcpIHtcbiAgICAgICAgaWYgKHNraXBPdGhlcikge1xuICAgICAgICAgIGNvbnN0IGFjdGlvbiA9IGhhbmRsZXIuZmluZChpID0+IGkuc2tpcE90aGVyKTtcbiAgICAgICAgICBpbnZhcmlhbnQoXG4gICAgICAgICAgICAhYWN0aW9uLFxuICAgICAgICAgICAgXCJDb25mbGljdGluZyAnc2tpcE90aGVyJyBwcm9wZXJ0eSB3aXRoIGFjdGlvblwiLFxuICAgICAgICAgICAgYWN0aW9uXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBoYW5kbGVyLnB1c2goe1xuICAgICAgICBzY29wZSxcbiAgICAgICAgbWV0aG9kLFxuICAgICAgICBzaG9ydGN1dCxcbiAgICAgICAgc2tpcE90aGVyXG4gICAgICB9KTtcbiAgICB9KTtcbiAgfTtcblxuICBjb25zdCB1bmJpbmRLZXlQcm9jZXNzID0gKFxuICAgIGtleXNTdHI6IHN0cmluZyxcbiAgICBkZWxldGVNZXRob2Q6IG51bGwgfCBub29wLFxuICAgIGRlbGV0ZVNjb3BlOiBzdHJpbmcgPSBERUZBVUxUX1NDT1BFXG4gICk6IHZvaWQgPT4ge1xuICAgIGdldEtleU1hcChrZXlzU3RyKS5mb3JFYWNoKCh7IGNvZGUsIHNob3J0Y3V0IH0pID0+IHtcbiAgICAgIGNvbnN0IGhhbmRsZXIgPSBoYW5kbGVyc1tjb2RlXTtcbiAgICAgIGlmIChBcnJheS5pc0FycmF5KGhhbmRsZXIpKSB7XG4gICAgICAgIGNvbnN0IGhhbmRsZXIgPSBoYW5kbGVyc1tjb2RlXS5maWx0ZXIoXG4gICAgICAgICAgKHsgc2NvcGUsIG1ldGhvZCwgc2hvcnRjdXQ6IG1ldGhvZFNob3J0Y3V0IH06IEhhbmRsZXIpID0+XG4gICAgICAgICAgICAhKFxuICAgICAgICAgICAgICBzY29wZSA9PT0gZGVsZXRlU2NvcGUgJiZcbiAgICAgICAgICAgICAgaXNFcUFycmF5KG1ldGhvZFNob3J0Y3V0Lm1vZHMsIHNob3J0Y3V0Lm1vZHMpICYmXG4gICAgICAgICAgICAgIGlzRXFBcnJheShtZXRob2RTaG9ydGN1dC5zcGVjaWFsLCBzaG9ydGN1dC5zcGVjaWFsKSAmJlxuICAgICAgICAgICAgICAoZGVsZXRlTWV0aG9kID09PSBudWxsID8gdHJ1ZSA6IG1ldGhvZCA9PT0gZGVsZXRlTWV0aG9kKVxuICAgICAgICAgICAgKVxuICAgICAgICApO1xuICAgICAgICBpZiAoaGFuZGxlci5sZW5ndGgpIHtcbiAgICAgICAgICBoYW5kbGVyc1tjb2RlXSA9IGhhbmRsZXI7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgZGVsZXRlIGhhbmRsZXJzW2NvZGVdO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSk7XG4gIH07XG5cbiAgY29uc3QgdW5iaW5kS2V5ID0gKFxuICAgIGtleXNTdHI6IHN0cmluZyxcbiAgICBzY29wZU9yTWV0aG9kOiBzdHJpbmcgfCBub29wLFxuICAgIG1ldGhvZE9yTnVsbDogbm9vcCA9ICgpID0+IHt9XG4gICkgPT4ge1xuICAgIGNvbnN0IGRlbGV0ZVNjb3BlOiBzdHJpbmcgPVxuICAgICAgdHlwZW9mIHNjb3BlT3JNZXRob2QgPT09ICdmdW5jdGlvbicgPyBERUZBVUxUX1NDT1BFIDogc2NvcGVPck1ldGhvZDtcbiAgICBjb25zdCBkZWxldGVNZXRob2Q6IG5vb3AgPVxuICAgICAgdHlwZW9mIHNjb3BlT3JNZXRob2QgPT09ICdmdW5jdGlvbicgPyBzY29wZU9yTWV0aG9kIDogbWV0aG9kT3JOdWxsO1xuICAgIHJldHVybiB1bmJpbmRLZXlQcm9jZXNzKGtleXNTdHIsIGRlbGV0ZU1ldGhvZCwgZGVsZXRlU2NvcGUpO1xuICB9O1xuXG4gIGNvbnN0IHVuc2FmZVVuYmluZEtleSA9IChrZXlzU3RyOiBzdHJpbmcsIHNjb3BlPzogc3RyaW5nKSA9PlxuICAgIHVuYmluZEtleVByb2Nlc3Moa2V5c1N0ciwgbnVsbCwgc2NvcGUpO1xuXG4gIGNvbnN0IGZpeGVkS2V5ID0gKGtleUNvZGU6IG51bWJlcik6IG51bWJlciA9PiB7XG4gICAgaWYgKGtleUNvZGUgPT09IDkzIHx8IGtleUNvZGUgPT09IDIyNCkge1xuICAgICAgcmV0dXJuIDkxO1xuICAgIH1cbiAgICByZXR1cm4ga2V5Q29kZTtcbiAgfTtcblxuICBjb25zdCBkaXNwYXRjaCA9IChlOiBLZXlib2FyZEV2ZW50KSA9PiB7XG4gICAgY29uc3QgeyBrZXlDb2RlIH0gPSBlO1xuICAgIGNvbnN0IGtleSA9IGZpeGVkS2V5KGtleUNvZGUpO1xuXG4gICAgbG9nKGBLZXkgJHtrZXl9YCk7XG4gICAgaWYgKCFmaWx0ZXJGbihlKSkge1xuICAgICAgbG9nKCdGaWx0ZXJlZCcsIGZpbHRlckZuKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyBmaXggZmlyZWZveCBiZWhhdmlvciB3aGVuIGNhcHMgbG9jayBmaXJlcyB0aHJlZSB0aW1lcyBvbmtleWRvd25cbiAgICAvLyBhbmQgZG9uJ3QgZmlyZSBhdCBhbGwgb25rZXl1cCAoRmlyZWZveCA3MilcbiAgICBpZiAoaXNGaXJlZm94ICYmIGtleSA9PT0gQ0FQU19MT0NLKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdXBkYXRlTW9kaWZpZXJzKGUpO1xuXG4gICAgaWYgKCF7fS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG1vZGlmaWVycywga2V5KSAmJiAhZG93bktleXMuaW5jbHVkZXMoa2V5KSkge1xuICAgICAgZG93bktleXMucHVzaChrZXkpO1xuICAgICAgbG9nKCdQdXNoIGRvd24ga2V5cycsIGRvd25LZXlzKTtcbiAgICB9XG4gICAgLy8gU2VlIGlmIHdlIG5lZWQgdG8gaWdub3JlIHRoZSBrZXlwcmVzcyAoZmlsdGVyKCkgY2FuIGNhbiBiZSBvdmVycmlkZGVuKVxuICAgIC8vIGJ5IGRlZmF1bHQgaWdub3JlIGtleSBwcmVzc2VzIGlmIGEgc2VsZWN0LCB0ZXh0YXJlYSwgb3IgaW5wdXQgaXMgZm9jdXNlZFxuICAgIC8vIGlmICghYXNzaWduS2V5LmZpbHRlci5jYWxsKHRoaXMsIGV2ZW50KSkgcmV0dXJuO1xuXG4gICAgLy8gYWJvcnQgaWYgbm8gcG90ZW50aWFsbHkgbWF0Y2hpbmcgc2hvcnRjdXRzIGZvdW5kXG4gICAgaWYgKCEoa2V5IGluIGhhbmRsZXJzKSkge1xuICAgICAgbG9nKCdLZXkgbm90IGluIGhhbmRsZXInKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCBjdXJyZW50SGFuZGxlcnMgPSBoYW5kbGVyc1trZXldLmZpbHRlcihcbiAgICAgICh7IHNjb3BlLCBzaG9ydGN1dDogeyBzcGVjaWFsLCBtb2RzIH0gfSkgPT4ge1xuICAgICAgICBpZiAoc2NvcGUgIT09IGFjdGl2ZVNjb3BlKSB7XG4gICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIChcbiAgICAgICAgICBpc0VxQXJyYXkoc3BlY2lhbCwgZG93bktleXMpICYmIGlzQm9vbEFycmF5VG9PYmplY3QobW9kcywgbW9kaWZpZXJzKVxuICAgICAgICApO1xuICAgICAgfVxuICAgICk7XG5cbiAgICBsb2coXG4gICAgICAnSGFuZGxlcnMgZm9yJyxcbiAgICAgIHtcbiAgICAgICAga2V5LFxuICAgICAgICBkb3duS2V5cyxcbiAgICAgICAgbW9kaWZpZXJzXG4gICAgICB9LFxuICAgICAgY3VycmVudEhhbmRsZXJzLFxuICAgICAgaGFuZGxlcnNcbiAgICApO1xuXG4gICAgY29uc3QgcHJpbWFyeUFjdGlvbjogSGFuZGxlciB8IHVuZGVmaW5lZCA9IGN1cnJlbnRIYW5kbGVycy5maW5kKFxuICAgICAgYWN0aW9uID0+IGFjdGlvbi5za2lwT3RoZXJcbiAgICApO1xuICAgIGlmIChwcmltYXJ5QWN0aW9uKSB7XG4gICAgICBwcmltYXJ5QWN0aW9uLm1ldGhvZChlKTtcbiAgICB9IGVsc2Uge1xuICAgICAgY3VycmVudEhhbmRsZXJzLmZvckVhY2goKHsgbWV0aG9kIH0pID0+IHtcbiAgICAgICAgbWV0aG9kKGUpO1xuICAgICAgfSk7XG4gICAgfVxuICB9O1xuXG4gIGNvbnN0IGNsZWFuVXAgPSAoZTogS2V5Ym9hcmRFdmVudCkgPT4ge1xuICAgIGNvbnN0IHsga2V5Q29kZSB9ID0gZTtcbiAgICBjb25zdCBrZXkgPSBmaXhlZEtleShrZXlDb2RlKTtcblxuICAgIC8vIGNsZWFuIGFsbCBmb3IgbWV0YS5cbiAgICAvLyBNYWluIHJlYXNvbiBpcyBjdHJsK3ogKG9yIGFueSBvdGhlciBuYXRpdmUgY29tbWFuZCBub3QgZmlyZXMgbGV0dGVyIGtleXVwIG9uIGVkaXRhYmxlIGlucHV0cylcbiAgICBpZiAoZS5rZXkgJiYgZS5rZXkudG9Mb3dlckNhc2UoKSA9PT0gJ21ldGEnKSB7XG4gICAgICBkb3duS2V5cyA9IFtdO1xuICAgIH0gZWxzZSB7XG4gICAgICBkb3duS2V5cyA9IGRvd25LZXlzLmZpbHRlcihpID0+IGkgIT09IGtleSk7XG4gICAgfVxuICAgIGxvZyhgQ2xlYW51cCBmb3IgJHtrZXl9YCwgZG93bktleXMpO1xuICB9O1xuXG4gIGNvbnN0IHVuYmluZFNjb3BlID0gKGRlbGV0ZVNjb3BlOiBzdHJpbmcpOiB2b2lkID0+IHtcbiAgICBPYmplY3Qua2V5cyhoYW5kbGVycykuZm9yRWFjaChrZXlDb2RlID0+IHtcbiAgICAgIGNvbnN0IGhhbmRsZXIgPSBoYW5kbGVyc1trZXlDb2RlXS5maWx0ZXIoXG4gICAgICAgICh7IHNjb3BlIH06IEhhbmRsZXIpID0+IHNjb3BlICE9PSBkZWxldGVTY29wZVxuICAgICAgKTtcbiAgICAgIGlmIChoYW5kbGVyLmxlbmd0aCkge1xuICAgICAgICBoYW5kbGVyc1trZXlDb2RlXSA9IGhhbmRsZXI7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBkZWxldGUgaGFuZGxlcnNba2V5Q29kZV07XG4gICAgICB9XG4gICAgfSk7XG4gIH07XG5cbiAgY29uc3Qgc2V0U2NvcGUgPSAoc2NvcGU6IHN0cmluZyk6IHZvaWQgPT4ge1xuICAgIGFjdGl2ZVNjb3BlID0gc2NvcGU7XG4gIH07XG5cbiAgY29uc3QgdW5iaW5kQWxsID0gKCk6IHZvaWQgPT4ge1xuICAgIGhhbmRsZXJzID0ge307XG4gIH07XG5cbiAgY29uc3QgcmVzZXQgPSAoKTogdm9pZCA9PiB7XG4gICAgZG93bktleXMgPSBbXTtcbiAgfTtcblxuICBjb25zdCBkZXN0cm95ID0gKCk6IHZvaWQgPT4ge1xuICAgIGRvd25LZXlzID0gW107XG4gICAgaGFuZGxlcnMgPSB7fTtcbiAgICBpZiAoZG9jKSB7XG4gICAgICBkb2MucmVtb3ZlRXZlbnRMaXN0ZW5lcigna2V5ZG93bicsIGRpc3BhdGNoKTtcbiAgICAgIGRvYy5yZW1vdmVFdmVudExpc3RlbmVyKCdrZXl1cCcsIGNsZWFuVXApO1xuICAgICAgLy8gUmVzZXQgYWxsIG9uIHdpbmRvdyBmb2N1c1xuICAgICAgd2luZG93LnJlbW92ZUV2ZW50TGlzdGVuZXIoJ2ZvY3VzJywgcmVzZXQpO1xuICAgIH1cbiAgfTtcblxuICBpZiAoZG9jKSB7XG4gICAgZG9jLmFkZEV2ZW50TGlzdGVuZXIoJ2tleWRvd24nLCBkaXNwYXRjaCk7XG4gICAgZG9jLmFkZEV2ZW50TGlzdGVuZXIoJ2tleXVwJywgY2xlYW5VcCk7XG4gICAgLy8gUmVzZXQgYWxsIG9uIHdpbmRvdyBmb2N1c1xuICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCdmb2N1cycsIHJlc2V0KTtcbiAgfVxuXG4gIHJldHVybiB7XG4gICAgYmluZDogYmluZEtleSxcbiAgICB1bmJpbmQ6IHVuYmluZEtleSxcbiAgICB1bnNhZmVVbmJpbmQ6IHVuc2FmZVVuYmluZEtleSxcbiAgICB1bmJpbmRTY29wZSxcbiAgICBzZXRTY29wZSxcbiAgICB1bmJpbmRBbGwsXG4gICAgZ2V0U2NvcGU6ICgpID0+IGFjdGl2ZVNjb3BlLFxuICAgIGRlc3Ryb3lcbiAgfTtcbn07XG4iXX0=
@@ -1,2 +0,0 @@
1
- export declare const isFirefox: boolean;
2
- export declare const isEditable: (el: HTMLElement) => boolean;
@@ -1,13 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.isEditable = exports.isFirefox = void 0;
7
- var isFirefox = navigator.userAgent.includes('Firefox');
8
- exports.isFirefox = isFirefox;
9
-
10
- var isEditable = el => el.isContentEditable || el.tagName === 'INPUT' || el.tagName === 'SELECT' || el.tagName === 'TEXTAREA';
11
-
12
- exports.isEditable = isEditable;
13
- //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9oZWxwZXJzL2Jyb3dzZXIudHMiXSwibmFtZXMiOlsiaXNGaXJlZm94IiwibmF2aWdhdG9yIiwidXNlckFnZW50IiwiaW5jbHVkZXMiLCJpc0VkaXRhYmxlIiwiZWwiLCJpc0NvbnRlbnRFZGl0YWJsZSIsInRhZ05hbWUiXSwibWFwcGluZ3MiOiI7Ozs7OztBQUFPLElBQU1BLFNBQVMsR0FBR0MsU0FBUyxDQUFDQyxTQUFWLENBQW9CQyxRQUFwQixDQUE2QixTQUE3QixDQUFsQjs7O0FBRUEsSUFBTUMsVUFBVSxHQUFJQyxFQUFELElBQ3hCQSxFQUFFLENBQUNDLGlCQUFILElBQ0FELEVBQUUsQ0FBQ0UsT0FBSCxLQUFlLE9BRGYsSUFFQUYsRUFBRSxDQUFDRSxPQUFILEtBQWUsUUFGZixJQUdBRixFQUFFLENBQUNFLE9BQUgsS0FBZSxVQUpWIiwic291cmNlc0NvbnRlbnQiOlsiZXhwb3J0IGNvbnN0IGlzRmlyZWZveCA9IG5hdmlnYXRvci51c2VyQWdlbnQuaW5jbHVkZXMoJ0ZpcmVmb3gnKTtcblxuZXhwb3J0IGNvbnN0IGlzRWRpdGFibGUgPSAoZWw6IEhUTUxFbGVtZW50KTogYm9vbGVhbiA9PlxuICBlbC5pc0NvbnRlbnRFZGl0YWJsZSB8fFxuICBlbC50YWdOYW1lID09PSAnSU5QVVQnIHx8XG4gIGVsLnRhZ05hbWUgPT09ICdTRUxFQ1QnIHx8XG4gIGVsLnRhZ05hbWUgPT09ICdURVhUQVJFQSc7XG4iXX0=
package/helpers/data.d.ts DELETED
@@ -1,4 +0,0 @@
1
- export declare const isEqArray: (arr1: (string | number)[], arr2: (string | number)[]) => boolean;
2
- export declare const isBoolArrayToObject: (arr: (string | number)[], obj: {
3
- [key: string]: boolean;
4
- }) => boolean;
package/helpers/data.js DELETED
@@ -1,32 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.isBoolArrayToObject = exports.isEqArray = void 0;
7
-
8
- var isEqArray = (arr1, arr2) => arr1.every((val, i) => arr2[i] === val); // TODO refactor to use strings
9
-
10
-
11
- exports.isEqArray = isEqArray;
12
-
13
- var isBoolArrayToObject = (arr, obj) => {
14
- for (var _key in obj) {
15
- if ({}.hasOwnProperty.call(obj, _key)) {
16
- var numKey = Number(_key);
17
-
18
- if (obj[_key] && !arr.includes(numKey)) {
19
- return false;
20
- }
21
-
22
- if (arr.includes(numKey) && !obj[_key]) {
23
- return false;
24
- }
25
- }
26
- }
27
-
28
- return true;
29
- };
30
-
31
- exports.isBoolArrayToObject = isBoolArrayToObject;
32
- //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9oZWxwZXJzL2RhdGEudHMiXSwibmFtZXMiOlsiaXNFcUFycmF5IiwiYXJyMSIsImFycjIiLCJldmVyeSIsInZhbCIsImkiLCJpc0Jvb2xBcnJheVRvT2JqZWN0IiwiYXJyIiwib2JqIiwia2V5IiwiaGFzT3duUHJvcGVydHkiLCJjYWxsIiwibnVtS2V5IiwiTnVtYmVyIiwiaW5jbHVkZXMiXSwibWFwcGluZ3MiOiI7Ozs7Ozs7QUFBTyxJQUFNQSxTQUFTLEdBQUcsQ0FDdkJDLElBRHVCLEVBRXZCQyxJQUZ1QixLQUdYRCxJQUFJLENBQUNFLEtBQUwsQ0FBVyxDQUFDQyxHQUFELEVBQU1DLENBQU4sS0FBWUgsSUFBSSxDQUFDRyxDQUFELENBQUosS0FBWUQsR0FBbkMsQ0FIUCxDLENBS1A7Ozs7O0FBQ08sSUFBTUUsbUJBQW1CLEdBQUcsQ0FDakNDLEdBRGlDLEVBRWpDQyxHQUZpQyxLQUdyQjtBQUNaLE9BQUssSUFBTUMsSUFBWCxJQUFrQkQsR0FBbEIsRUFBdUI7QUFDckIsUUFBSSxHQUFHRSxjQUFILENBQWtCQyxJQUFsQixDQUF1QkgsR0FBdkIsRUFBNEJDLElBQTVCLENBQUosRUFBc0M7QUFDcEMsVUFBTUcsTUFBTSxHQUFHQyxNQUFNLENBQUNKLElBQUQsQ0FBckI7O0FBQ0EsVUFBSUQsR0FBRyxDQUFDQyxJQUFELENBQUgsSUFBWSxDQUFDRixHQUFHLENBQUNPLFFBQUosQ0FBYUYsTUFBYixDQUFqQixFQUF1QztBQUNyQyxlQUFPLEtBQVA7QUFDRDs7QUFDRCxVQUFJTCxHQUFHLENBQUNPLFFBQUosQ0FBYUYsTUFBYixLQUF3QixDQUFDSixHQUFHLENBQUNDLElBQUQsQ0FBaEMsRUFBdUM7QUFDckMsZUFBTyxLQUFQO0FBQ0Q7QUFDRjtBQUNGOztBQUNELFNBQU8sSUFBUDtBQUNELENBaEJNIiwic291cmNlc0NvbnRlbnQiOlsiZXhwb3J0IGNvbnN0IGlzRXFBcnJheSA9IChcbiAgYXJyMTogKHN0cmluZyB8IG51bWJlcilbXSxcbiAgYXJyMjogKHN0cmluZyB8IG51bWJlcilbXVxuKTogYm9vbGVhbiA9PiBhcnIxLmV2ZXJ5KCh2YWwsIGkpID0+IGFycjJbaV0gPT09IHZhbCk7XG5cbi8vIFRPRE8gcmVmYWN0b3IgdG8gdXNlIHN0cmluZ3NcbmV4cG9ydCBjb25zdCBpc0Jvb2xBcnJheVRvT2JqZWN0ID0gKFxuICBhcnI6IChzdHJpbmcgfCBudW1iZXIpW10sXG4gIG9iajogeyBba2V5OiBzdHJpbmddOiBib29sZWFuIH1cbik6IGJvb2xlYW4gPT4ge1xuICBmb3IgKGNvbnN0IGtleSBpbiBvYmopIHtcbiAgICBpZiAoe30uaGFzT3duUHJvcGVydHkuY2FsbChvYmosIGtleSkpIHtcbiAgICAgIGNvbnN0IG51bUtleSA9IE51bWJlcihrZXkpO1xuICAgICAgaWYgKG9ialtrZXldICYmICFhcnIuaW5jbHVkZXMobnVtS2V5KSkge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICB9XG4gICAgICBpZiAoYXJyLmluY2x1ZGVzKG51bUtleSkgJiYgIW9ialtrZXldKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgIH1cbiAgICB9XG4gIH1cbiAgcmV0dXJuIHRydWU7XG59O1xuIl19
@@ -1,11 +0,0 @@
1
- import { ModifierKeys } from '../constants';
2
- export interface ParsedShortcut {
3
- mods: Array<keyof ModifierKeys>;
4
- special: number[];
5
- }
6
- export interface KeyMap {
7
- code: number;
8
- shortcut: ParsedShortcut;
9
- }
10
- export declare const getKeyCode: (key: string) => number;
11
- export declare const getKeyMap: (keysStr: string) => KeyMap[];
package/helpers/keymap.js DELETED
@@ -1,52 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.getKeyMap = exports.getKeyCode = void 0;
7
-
8
- var _constants = require("../constants");
9
-
10
- var getKeyCode = key => _constants.SPECIAL[key] || key.toUpperCase().charCodeAt(0);
11
-
12
- exports.getKeyCode = getKeyCode;
13
-
14
- var getMods = keys => keys.reduce((acc, key) => {
15
- if ({}.hasOwnProperty.call(_constants.MODIFIERS, key)) {
16
- acc.mods.push(_constants.MODIFIERS[key]);
17
- } else {
18
- acc.special.push(_constants.SPECIAL[key] || key.toUpperCase().charCodeAt(0));
19
- }
20
-
21
- return acc;
22
- }, {
23
- mods: [],
24
- special: []
25
- });
26
-
27
- var getCombinations = keysStr => {
28
- var cleanKeys = keysStr.replace(/\s/g, '');
29
- var keys = cleanKeys.split(',');
30
-
31
- if (keys[keys.length - 1] === '') {
32
- keys[keys.length - 2] += ',';
33
- }
34
-
35
- return keys;
36
- };
37
-
38
- var getKeyMap = keysStr => {
39
- var keymap = getCombinations(keysStr);
40
- return keymap.map(keyCmd => {
41
- var keys = keyCmd.split('+');
42
- var key = keys[keys.length - 1];
43
- var code = getKeyCode(key);
44
- return {
45
- code,
46
- shortcut: getMods(keys)
47
- };
48
- });
49
- };
50
-
51
- exports.getKeyMap = getKeyMap;
52
- //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9oZWxwZXJzL2tleW1hcC50cyJdLCJuYW1lcyI6WyJnZXRLZXlDb2RlIiwia2V5IiwiU1BFQ0lBTCIsInRvVXBwZXJDYXNlIiwiY2hhckNvZGVBdCIsImdldE1vZHMiLCJrZXlzIiwicmVkdWNlIiwiYWNjIiwiaGFzT3duUHJvcGVydHkiLCJjYWxsIiwiTU9ESUZJRVJTIiwibW9kcyIsInB1c2giLCJzcGVjaWFsIiwiZ2V0Q29tYmluYXRpb25zIiwia2V5c1N0ciIsImNsZWFuS2V5cyIsInJlcGxhY2UiLCJzcGxpdCIsImxlbmd0aCIsImdldEtleU1hcCIsImtleW1hcCIsIm1hcCIsImtleUNtZCIsImNvZGUiLCJzaG9ydGN1dCJdLCJtYXBwaW5ncyI6Ijs7Ozs7OztBQUFBOztBQVdPLElBQU1BLFVBQVUsR0FBSUMsR0FBRCxJQUN4QkMsbUJBQVFELEdBQVIsS0FBZ0JBLEdBQUcsQ0FBQ0UsV0FBSixHQUFrQkMsVUFBbEIsQ0FBNkIsQ0FBN0IsQ0FEWDs7OztBQUdQLElBQU1DLE9BQU8sR0FBSUMsSUFBRCxJQUNkQSxJQUFJLENBQUNDLE1BQUwsQ0FDRSxDQUFDQyxHQUFELEVBQU1QLEdBQU4sS0FBYztBQUNaLE1BQUksR0FBR1EsY0FBSCxDQUFrQkMsSUFBbEIsQ0FBdUJDLG9CQUF2QixFQUFrQ1YsR0FBbEMsQ0FBSixFQUE0QztBQUMxQ08sSUFBQUEsR0FBRyxDQUFDSSxJQUFKLENBQVNDLElBQVQsQ0FBY0YscUJBQVVWLEdBQVYsQ0FBZDtBQUNELEdBRkQsTUFFTztBQUNMTyxJQUFBQSxHQUFHLENBQUNNLE9BQUosQ0FBWUQsSUFBWixDQUFpQlgsbUJBQVFELEdBQVIsS0FBZ0JBLEdBQUcsQ0FBQ0UsV0FBSixHQUFrQkMsVUFBbEIsQ0FBNkIsQ0FBN0IsQ0FBakM7QUFDRDs7QUFDRCxTQUFPSSxHQUFQO0FBQ0QsQ0FSSCxFQVNFO0FBQ0VJLEVBQUFBLElBQUksRUFBRSxFQURSO0FBRUVFLEVBQUFBLE9BQU8sRUFBRTtBQUZYLENBVEYsQ0FERjs7QUFnQkEsSUFBTUMsZUFBZSxHQUFJQyxPQUFELElBQStCO0FBQ3JELE1BQU1DLFNBQVMsR0FBR0QsT0FBTyxDQUFDRSxPQUFSLENBQWdCLEtBQWhCLEVBQXVCLEVBQXZCLENBQWxCO0FBQ0EsTUFBTVosSUFBSSxHQUFHVyxTQUFTLENBQUNFLEtBQVYsQ0FBZ0IsR0FBaEIsQ0FBYjs7QUFDQSxNQUFJYixJQUFJLENBQUNBLElBQUksQ0FBQ2MsTUFBTCxHQUFjLENBQWYsQ0FBSixLQUEwQixFQUE5QixFQUFrQztBQUNoQ2QsSUFBQUEsSUFBSSxDQUFDQSxJQUFJLENBQUNjLE1BQUwsR0FBYyxDQUFmLENBQUosSUFBeUIsR0FBekI7QUFDRDs7QUFFRCxTQUFPZCxJQUFQO0FBQ0QsQ0FSRDs7QUFVTyxJQUFNZSxTQUFTLEdBQUlMLE9BQUQsSUFBK0I7QUFDdEQsTUFBTU0sTUFBTSxHQUFHUCxlQUFlLENBQUNDLE9BQUQsQ0FBOUI7QUFDQSxTQUFPTSxNQUFNLENBQUNDLEdBQVAsQ0FBV0MsTUFBTSxJQUFJO0FBQzFCLFFBQU1sQixJQUFJLEdBQUdrQixNQUFNLENBQUNMLEtBQVAsQ0FBYSxHQUFiLENBQWI7QUFDQSxRQUFNbEIsR0FBRyxHQUFHSyxJQUFJLENBQUNBLElBQUksQ0FBQ2MsTUFBTCxHQUFjLENBQWYsQ0FBaEI7QUFDQSxRQUFNSyxJQUFJLEdBQUd6QixVQUFVLENBQUNDLEdBQUQsQ0FBdkI7QUFFQSxXQUFPO0FBQ0x3QixNQUFBQSxJQURLO0FBRUxDLE1BQUFBLFFBQVEsRUFBRXJCLE9BQU8sQ0FBQ0MsSUFBRDtBQUZaLEtBQVA7QUFJRCxHQVRNLENBQVA7QUFVRCxDQVpNIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgTU9ESUZJRVJTLCBTUEVDSUFMLCBNb2RpZmllcktleXMsIE1vZGlmaWVycyB9IGZyb20gJy4uL2NvbnN0YW50cyc7XG5cbmV4cG9ydCBpbnRlcmZhY2UgUGFyc2VkU2hvcnRjdXQge1xuICBtb2RzOiBBcnJheTxrZXlvZiBNb2RpZmllcktleXM+O1xuICBzcGVjaWFsOiBudW1iZXJbXTtcbn1cbmV4cG9ydCBpbnRlcmZhY2UgS2V5TWFwIHtcbiAgY29kZTogbnVtYmVyO1xuICBzaG9ydGN1dDogUGFyc2VkU2hvcnRjdXQ7XG59XG5cbmV4cG9ydCBjb25zdCBnZXRLZXlDb2RlID0gKGtleTogc3RyaW5nKTogbnVtYmVyID0+XG4gIFNQRUNJQUxba2V5XSB8fCBrZXkudG9VcHBlckNhc2UoKS5jaGFyQ29kZUF0KDApO1xuXG5jb25zdCBnZXRNb2RzID0gKGtleXM6IHN0cmluZ1tdKTogUGFyc2VkU2hvcnRjdXQgPT5cbiAga2V5cy5yZWR1Y2UoXG4gICAgKGFjYywga2V5KSA9PiB7XG4gICAgICBpZiAoe30uaGFzT3duUHJvcGVydHkuY2FsbChNT0RJRklFUlMsIGtleSkpIHtcbiAgICAgICAgYWNjLm1vZHMucHVzaChNT0RJRklFUlNba2V5IGFzIGtleW9mIE1vZGlmaWVyc10pO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgYWNjLnNwZWNpYWwucHVzaChTUEVDSUFMW2tleV0gfHwga2V5LnRvVXBwZXJDYXNlKCkuY2hhckNvZGVBdCgwKSk7XG4gICAgICB9XG4gICAgICByZXR1cm4gYWNjO1xuICAgIH0sXG4gICAge1xuICAgICAgbW9kczogW10sXG4gICAgICBzcGVjaWFsOiBbXVxuICAgIH0gYXMgUGFyc2VkU2hvcnRjdXRcbiAgKTtcblxuY29uc3QgZ2V0Q29tYmluYXRpb25zID0gKGtleXNTdHI6IHN0cmluZyk6IHN0cmluZ1tdID0+IHtcbiAgY29uc3QgY2xlYW5LZXlzID0ga2V5c1N0ci5yZXBsYWNlKC9cXHMvZywgJycpO1xuICBjb25zdCBrZXlzID0gY2xlYW5LZXlzLnNwbGl0KCcsJyk7XG4gIGlmIChrZXlzW2tleXMubGVuZ3RoIC0gMV0gPT09ICcnKSB7XG4gICAga2V5c1trZXlzLmxlbmd0aCAtIDJdICs9ICcsJztcbiAgfVxuXG4gIHJldHVybiBrZXlzO1xufTtcblxuZXhwb3J0IGNvbnN0IGdldEtleU1hcCA9IChrZXlzU3RyOiBzdHJpbmcpOiBLZXlNYXBbXSA9PiB7XG4gIGNvbnN0IGtleW1hcCA9IGdldENvbWJpbmF0aW9ucyhrZXlzU3RyKTtcbiAgcmV0dXJuIGtleW1hcC5tYXAoa2V5Q21kID0+IHtcbiAgICBjb25zdCBrZXlzID0ga2V5Q21kLnNwbGl0KCcrJyk7XG4gICAgY29uc3Qga2V5ID0ga2V5c1trZXlzLmxlbmd0aCAtIDFdO1xuICAgIGNvbnN0IGNvZGUgPSBnZXRLZXlDb2RlKGtleSk7XG5cbiAgICByZXR1cm4ge1xuICAgICAgY29kZSxcbiAgICAgIHNob3J0Y3V0OiBnZXRNb2RzKGtleXMpXG4gICAgfTtcbiAgfSk7XG59O1xuIl19