@vielzeug/keymap 2.2.0 → 26.10.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 +21 -22
- package/dist/_dev.cjs +1 -1
- package/dist/_dev.cjs.map +1 -1
- package/dist/_dev.js +1 -5
- package/dist/_dev.js.map +1 -1
- package/dist/conflicts.cjs +1 -1
- package/dist/conflicts.cjs.map +1 -1
- package/dist/conflicts.js +1 -14
- package/dist/conflicts.js.map +1 -1
- package/dist/errors.cjs +1 -1
- package/dist/errors.cjs.map +1 -1
- package/dist/errors.d.ts +3 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +1 -9
- package/dist/errors.js.map +1 -1
- package/dist/format.cjs +1 -1
- package/dist/format.cjs.map +1 -1
- package/dist/format.d.ts +14 -0
- package/dist/format.d.ts.map +1 -1
- package/dist/format.js +1 -51
- package/dist/format.js.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +4 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -6
- package/dist/keymap.cjs +1 -1
- package/dist/keymap.cjs.map +1 -1
- package/dist/keymap.d.ts +15 -13
- package/dist/keymap.d.ts.map +1 -1
- package/dist/keymap.iife.js +1 -1
- package/dist/keymap.iife.js.map +1 -1
- package/dist/keymap.js +1 -1
- package/dist/keymap.js.map +1 -1
- package/dist/parse.cjs +1 -0
- package/dist/parse.d.ts +13 -0
- package/dist/parse.d.ts.map +1 -0
- package/dist/parse.js +1 -0
- package/dist/parser.cjs +1 -1
- package/dist/parser.cjs.map +1 -1
- package/dist/parser.d.ts +8 -0
- package/dist/parser.d.ts.map +1 -1
- package/dist/parser.js +1 -73
- package/dist/parser.js.map +1 -1
- package/dist/types.d.ts +70 -49
- package/dist/types.d.ts.map +1 -1
- package/package.json +19 -7
package/dist/parser.js
CHANGED
|
@@ -1,74 +1,2 @@
|
|
|
1
|
-
import
|
|
2
|
-
//#region src/parser.ts
|
|
3
|
-
function t() {
|
|
4
|
-
if (typeof navigator > "u") return "ctrl";
|
|
5
|
-
let e = navigator.userAgentData?.platform ?? navigator.platform ?? "";
|
|
6
|
-
return /mac/i.test(e) ? "meta" : "ctrl";
|
|
7
|
-
}
|
|
8
|
-
var n = {
|
|
9
|
-
alt: "alt",
|
|
10
|
-
cmd: "meta",
|
|
11
|
-
command: "meta",
|
|
12
|
-
control: "ctrl",
|
|
13
|
-
ctrl: "ctrl",
|
|
14
|
-
meta: "meta",
|
|
15
|
-
opt: "alt",
|
|
16
|
-
option: "alt",
|
|
17
|
-
shift: "shift",
|
|
18
|
-
win: "meta"
|
|
19
|
-
}, r = {
|
|
20
|
-
del: "delete",
|
|
21
|
-
down: "arrowdown",
|
|
22
|
-
esc: "escape",
|
|
23
|
-
left: "arrowleft",
|
|
24
|
-
right: "arrowright",
|
|
25
|
-
space: " ",
|
|
26
|
-
spacebar: " ",
|
|
27
|
-
up: "arrowup"
|
|
28
|
-
};
|
|
29
|
-
function i(t, i) {
|
|
30
|
-
let a = t.trim().split("+").filter(Boolean).map((e) => e.toLowerCase());
|
|
31
|
-
if (a.length === 0) throw new e(`Invalid shortcut step: "${t}"`);
|
|
32
|
-
let o = {
|
|
33
|
-
...n,
|
|
34
|
-
mod: i
|
|
35
|
-
}, s = /* @__PURE__ */ new Set(), c = [];
|
|
36
|
-
for (let e of a) {
|
|
37
|
-
let t = Object.hasOwn(o, e) ? o[e] : void 0;
|
|
38
|
-
t ? s.add(t) : c.push(e);
|
|
39
|
-
}
|
|
40
|
-
if (c.length === 0) throw new e(`Invalid shortcut step: "${t}"`);
|
|
41
|
-
if (c.length > 1) throw new e(`Ambiguous shortcut step: "${t}" — multiple non-modifier keys found`);
|
|
42
|
-
let l = c[0];
|
|
43
|
-
return {
|
|
44
|
-
key: Object.hasOwn(r, l) ? r[l] : l,
|
|
45
|
-
modifiers: s
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
function a(e, n = t()) {
|
|
49
|
-
try {
|
|
50
|
-
return i(e, n);
|
|
51
|
-
} catch {
|
|
52
|
-
return null;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
function o(n, r = t()) {
|
|
56
|
-
let a = n.trim().split(/\s+/).filter(Boolean);
|
|
57
|
-
if (a.length === 0) throw new e("Shortcut must contain at least one key step");
|
|
58
|
-
return a.map((e) => i(e, r));
|
|
59
|
-
}
|
|
60
|
-
function s(e) {
|
|
61
|
-
return e.map((e) => {
|
|
62
|
-
let t = [...e.modifiers].sort().join("+");
|
|
63
|
-
return t ? `${t}+${e.key}` : e.key;
|
|
64
|
-
}).join(" ");
|
|
65
|
-
}
|
|
66
|
-
function c(e, t) {
|
|
67
|
-
if (typeof e.key != "string" || e.key.toLowerCase() !== t.key) return !1;
|
|
68
|
-
let { modifiers: n } = t;
|
|
69
|
-
return e.altKey === n.has("alt") && e.ctrlKey === n.has("ctrl") && e.metaKey === n.has("meta") && e.shiftKey === n.has("shift");
|
|
70
|
-
}
|
|
71
|
-
//#endregion
|
|
72
|
-
export { s as canonicalizeShortcut, t as detectModKey, c as matchStep, o as parseShortcut, a as parseStep };
|
|
73
|
-
|
|
1
|
+
import{KeymapParseError as e}from"./errors.js";function detectModKey(){if(typeof navigator>`u`)return`ctrl`;let e=navigator.userAgentData?.platform??navigator.platform??``;return/mac/i.test(e)?`meta`:`ctrl`}var t={alt:`alt`,cmd:`meta`,command:`meta`,control:`ctrl`,ctrl:`ctrl`,meta:`meta`,opt:`alt`,option:`alt`,shift:`shift`,win:`meta`},n={del:`delete`,down:`arrowdown`,esc:`escape`,left:`arrowleft`,right:`arrowright`,space:` `,spacebar:` `,up:`arrowup`};function parseStepStrict(r,i){let a=r.trim().split(`+`).filter(Boolean).map(e=>e.toLowerCase());if(a.length===0)throw new e(`Invalid shortcut step: "${r}"`);let o={...t,mod:i},s=new Set,c=[];for(let e of a){let t=Object.hasOwn(o,e)?o[e]:void 0;t?s.add(t):c.push(e)}if(c.length===0)throw new e(`Invalid shortcut step: "${r}"`);if(c.length>1)throw new e(`Ambiguous shortcut step: "${r}" — multiple non-modifier keys found`);let l=c[0];return{key:Object.hasOwn(n,l)?n[l]:l,modifiers:s}}function parseStep(e,t=detectModKey()){try{return parseStepStrict(e,t)}catch{return null}}function parseShortcut(t,n=detectModKey()){let r=t.trim().split(/\s+/).filter(Boolean);if(r.length===0)throw new e(`Shortcut must contain at least one key step`);return r.map(e=>parseStepStrict(e,n))}function canonicalizeShortcut(e){return e.map(e=>{let t=[...e.modifiers].sort().join(`+`);return t?`${t}+${e.key}`:e.key}).join(` `)}function matchStep(e,t){if(typeof e.key!=`string`||e.key.toLowerCase()!==t.key)return!1;let{modifiers:n}=t;return e.altKey===n.has(`alt`)&&e.ctrlKey===n.has(`ctrl`)&&e.metaKey===n.has(`meta`)&&e.shiftKey===n.has(`shift`)}function matchKey(e,t,n=detectModKey()){let r=parseStep(t,n);return r!==null&&matchStep(e,r)}export{canonicalizeShortcut,detectModKey,matchKey,matchStep,parseShortcut,parseStep};
|
|
74
2
|
//# sourceMappingURL=parser.js.map
|
package/dist/parser.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parser.js","names":[],"sources":["../src/parser.ts"],"sourcesContent":["import { KeymapParseError } from './errors';\n\nexport type ModifierKey = 'alt' | 'ctrl' | 'meta' | 'shift';\n\nexport type ShortcutStep = {\n key: string;\n modifiers: Set<ModifierKey>;\n};\n\nexport type Shortcut = ShortcutStep[];\n\nexport function detectModKey(): 'ctrl' | 'meta' {\n if (typeof navigator === 'undefined') return 'ctrl';\n\n const platform =\n (navigator as Navigator & { userAgentData?: { platform?: string } }).userAgentData?.platform ??\n navigator.platform ??\n '';\n\n return /mac/i.test(platform) ? 'meta' : 'ctrl';\n}\n\nconst MODIFIER_ALIASES_BASE: Record<string, ModifierKey> = {\n alt: 'alt',\n cmd: 'meta',\n command: 'meta',\n control: 'ctrl',\n ctrl: 'ctrl',\n meta: 'meta',\n opt: 'alt',\n option: 'alt',\n shift: 'shift',\n win: 'meta',\n};\n\nconst SPECIAL_KEY_ALIASES: Record<string, string> = {\n del: 'delete',\n down: 'arrowdown',\n esc: 'escape',\n left: 'arrowleft',\n right: 'arrowright',\n space: ' ',\n spacebar: ' ',\n up: 'arrowup',\n};\n\nfunction parseStepStrict(raw: string, modKey: 'ctrl' | 'meta'): ShortcutStep {\n const parts = raw\n .trim()\n .split('+')\n .filter(Boolean)\n .map((part) => part.toLowerCase());\n\n if (parts.length === 0) throw new KeymapParseError(`Invalid shortcut step: \"${raw}\"`);\n\n const aliases: Record<string, ModifierKey> = { ...MODIFIER_ALIASES_BASE, mod: modKey };\n const modifiers = new Set<ModifierKey>();\n const keyParts: string[] = [];\n\n for (const part of parts) {\n const modifier = Object.hasOwn(aliases, part) ? aliases[part]! : undefined;\n\n if (modifier) modifiers.add(modifier);\n else keyParts.push(part);\n }\n\n if (keyParts.length === 0) throw new KeymapParseError(`Invalid shortcut step: \"${raw}\"`);\n\n if (keyParts.length > 1) {\n throw new KeymapParseError(`Ambiguous shortcut step: \"${raw}\" — multiple non-modifier keys found`);\n }\n\n const rawKey = keyParts[0]!;\n const key = Object.hasOwn(SPECIAL_KEY_ALIASES, rawKey) ? SPECIAL_KEY_ALIASES[rawKey]! : rawKey;\n\n return { key, modifiers };\n}\n\nexport function parseStep(raw: string, modKey: 'ctrl' | 'meta' = detectModKey()): ShortcutStep | null {\n try {\n return parseStepStrict(raw, modKey);\n } catch {\n return null;\n }\n}\n\nexport function parseShortcut(raw: string, modKey: 'ctrl' | 'meta' = detectModKey()): Shortcut {\n const steps = raw.trim().split(/\\s+/).filter(Boolean);\n\n if (steps.length === 0) throw new KeymapParseError('Shortcut must contain at least one key step');\n\n return steps.map((step) => parseStepStrict(step, modKey));\n}\n\nexport function canonicalizeShortcut(steps: readonly ShortcutStep[]): string {\n return steps\n .map((step) => {\n const modifiers = [...step.modifiers].sort().join('+');\n\n return modifiers ? `${modifiers}+${step.key}` : step.key;\n })\n .join(' ');\n}\n\nexport function matchStep(event: KeyboardEvent, step: ShortcutStep): boolean {\n // Headless usage (SSR, non-DOM `EventTarget`s, hand-built test events) means `event` isn't\n // guaranteed to be a real `KeyboardEvent` at runtime even though the type says so — treat a\n // missing/non-string `key` as \"doesn't match\" rather than throwing inside the event listener.\n if (typeof event.key !== 'string') return false;\n\n if (event.key.toLowerCase() !== step.key) return false;\n\n const { modifiers } = step;\n\n return (\n event.altKey === modifiers.has('alt') &&\n event.ctrlKey === modifiers.has('ctrl') &&\n event.metaKey === modifiers.has('meta') &&\n event.shiftKey === modifiers.has('shift')\n );\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"parser.js","names":[],"sources":["../src/parser.ts"],"sourcesContent":["import { KeymapParseError } from './errors';\n\nexport type ModifierKey = 'alt' | 'ctrl' | 'meta' | 'shift';\n\nexport type ShortcutStep = {\n key: string;\n modifiers: Set<ModifierKey>;\n};\n\nexport type Shortcut = ShortcutStep[];\n\nexport function detectModKey(): 'ctrl' | 'meta' {\n if (typeof navigator === 'undefined') return 'ctrl';\n\n const platform =\n (navigator as Navigator & { userAgentData?: { platform?: string } }).userAgentData?.platform ??\n navigator.platform ??\n '';\n\n return /mac/i.test(platform) ? 'meta' : 'ctrl';\n}\n\nconst MODIFIER_ALIASES_BASE: Record<string, ModifierKey> = {\n alt: 'alt',\n cmd: 'meta',\n command: 'meta',\n control: 'ctrl',\n ctrl: 'ctrl',\n meta: 'meta',\n opt: 'alt',\n option: 'alt',\n shift: 'shift',\n win: 'meta',\n};\n\nconst SPECIAL_KEY_ALIASES: Record<string, string> = {\n del: 'delete',\n down: 'arrowdown',\n esc: 'escape',\n left: 'arrowleft',\n right: 'arrowright',\n space: ' ',\n spacebar: ' ',\n up: 'arrowup',\n};\n\nfunction parseStepStrict(raw: string, modKey: 'ctrl' | 'meta'): ShortcutStep {\n const parts = raw\n .trim()\n .split('+')\n .filter(Boolean)\n .map((part) => part.toLowerCase());\n\n if (parts.length === 0) throw new KeymapParseError(`Invalid shortcut step: \"${raw}\"`);\n\n const aliases: Record<string, ModifierKey> = { ...MODIFIER_ALIASES_BASE, mod: modKey };\n const modifiers = new Set<ModifierKey>();\n const keyParts: string[] = [];\n\n for (const part of parts) {\n const modifier = Object.hasOwn(aliases, part) ? aliases[part]! : undefined;\n\n if (modifier) modifiers.add(modifier);\n else keyParts.push(part);\n }\n\n if (keyParts.length === 0) throw new KeymapParseError(`Invalid shortcut step: \"${raw}\"`);\n\n if (keyParts.length > 1) {\n throw new KeymapParseError(`Ambiguous shortcut step: \"${raw}\" — multiple non-modifier keys found`);\n }\n\n const rawKey = keyParts[0]!;\n const key = Object.hasOwn(SPECIAL_KEY_ALIASES, rawKey) ? SPECIAL_KEY_ALIASES[rawKey]! : rawKey;\n\n return { key, modifiers };\n}\n\nexport function parseStep(raw: string, modKey: 'ctrl' | 'meta' = detectModKey()): ShortcutStep | null {\n try {\n return parseStepStrict(raw, modKey);\n } catch {\n return null;\n }\n}\n\nexport function parseShortcut(raw: string, modKey: 'ctrl' | 'meta' = detectModKey()): Shortcut {\n const steps = raw.trim().split(/\\s+/).filter(Boolean);\n\n if (steps.length === 0) throw new KeymapParseError('Shortcut must contain at least one key step');\n\n return steps.map((step) => parseStepStrict(step, modKey));\n}\n\nexport function canonicalizeShortcut(steps: readonly ShortcutStep[]): string {\n return steps\n .map((step) => {\n const modifiers = [...step.modifiers].sort().join('+');\n\n return modifiers ? `${modifiers}+${step.key}` : step.key;\n })\n .join(' ');\n}\n\nexport function matchStep(event: KeyboardEvent, step: ShortcutStep): boolean {\n // Headless usage (SSR, non-DOM `EventTarget`s, hand-built test events) means `event` isn't\n // guaranteed to be a real `KeyboardEvent` at runtime even though the type says so — treat a\n // missing/non-string `key` as \"doesn't match\" rather than throwing inside the event listener.\n if (typeof event.key !== 'string') return false;\n\n if (event.key.toLowerCase() !== step.key) return false;\n\n const { modifiers } = step;\n\n return (\n event.altKey === modifiers.has('alt') &&\n event.ctrlKey === modifiers.has('ctrl') &&\n event.metaKey === modifiers.has('meta') &&\n event.shiftKey === modifiers.has('shift')\n );\n}\n\n/**\n * Match a keyboard event against a single shortcut pattern such as `'ArrowDown'`,\n * `'esc'`, `'mod+k'`, or `'shift+Home'`. Aliases and `mod` resolve through the same\n * parser `createKeymap` uses, and modifier state must match exactly: `ArrowDown`\n * does not match Ctrl+ArrowDown. Returns `false` for unparseable patterns instead\n * of throwing, so it is safe inside event listeners.\n */\nexport function matchKey(event: KeyboardEvent, pattern: string, modKey: 'ctrl' | 'meta' = detectModKey()): boolean {\n const step = parseStep(pattern, modKey);\n\n return step !== null && matchStep(event, step);\n}\n"],"mappings":"+CAWA,SAAgB,cAAgC,CAC9C,GAAI,OAAO,UAAc,IAAa,MAAO,OAE7C,IAAM,EACH,UAAoE,eAAe,UACpF,UAAU,UACV,GAEF,MAAO,OAAO,KAAK,CAAQ,EAAI,OAAS,MAC1C,CAEA,IAAM,EAAqD,CACzD,IAAK,MACL,IAAK,OACL,QAAS,OACT,QAAS,OACT,KAAM,OACN,KAAM,OACN,IAAK,MACL,OAAQ,MACR,MAAO,QACP,IAAK,MACP,EAEM,EAA8C,CAClD,IAAK,SACL,KAAM,YACN,IAAK,SACL,KAAM,YACN,MAAO,aACP,MAAO,IACP,SAAU,IACV,GAAI,SACN,EAEA,SAAS,gBAAgB,EAAa,EAAuC,CAC3E,IAAM,EAAQ,EACX,KAAK,CAAC,CACN,MAAM,GAAG,CAAC,CACV,OAAO,OAAO,CAAC,CACf,IAAK,GAAS,EAAK,YAAY,CAAC,EAEnC,GAAI,EAAM,SAAW,EAAG,MAAM,IAAI,EAAiB,2BAA2B,EAAI,EAAE,EAEpF,IAAM,EAAuC,CAAE,GAAG,EAAuB,IAAK,CAAO,EAC/E,EAAY,IAAI,IAChB,EAAqB,CAAC,EAE5B,IAAK,IAAM,KAAQ,EAAO,CACxB,IAAM,EAAW,OAAO,OAAO,EAAS,CAAI,EAAI,EAAQ,GAAS,IAAA,GAE7D,EAAU,EAAU,IAAI,CAAQ,EAC/B,EAAS,KAAK,CAAI,CACzB,CAEA,GAAI,EAAS,SAAW,EAAG,MAAM,IAAI,EAAiB,2BAA2B,EAAI,EAAE,EAEvF,GAAI,EAAS,OAAS,EACpB,MAAM,IAAI,EAAiB,6BAA6B,EAAI,qCAAqC,EAGnG,IAAM,EAAS,EAAS,GAGxB,MAAO,CAAE,IAFG,OAAO,OAAO,EAAqB,CAAM,EAAI,EAAoB,GAAW,EAE1E,WAAU,CAC1B,CAEA,SAAgB,UAAU,EAAa,EAA0B,aAAa,EAAwB,CACpG,GAAI,CACF,OAAO,gBAAgB,EAAK,CAAM,CACpC,MAAQ,CACN,OAAO,IACT,CACF,CAEA,SAAgB,cAAc,EAAa,EAA0B,aAAa,EAAa,CAC7F,IAAM,EAAQ,EAAI,KAAK,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,OAAO,OAAO,EAEpD,GAAI,EAAM,SAAW,EAAG,MAAM,IAAI,EAAiB,6CAA6C,EAEhG,OAAO,EAAM,IAAK,GAAS,gBAAgB,EAAM,CAAM,CAAC,CAC1D,CAEA,SAAgB,qBAAqB,EAAwC,CAC3E,OAAO,EACJ,IAAK,GAAS,CACb,IAAM,EAAY,CAAC,GAAG,EAAK,SAAS,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,GAAG,EAErD,OAAO,EAAY,GAAG,EAAU,GAAG,EAAK,MAAQ,EAAK,GACvD,CAAC,CAAC,CACD,KAAK,GAAG,CACb,CAEA,SAAgB,UAAU,EAAsB,EAA6B,CAM3E,GAFI,OAAO,EAAM,KAAQ,UAErB,EAAM,IAAI,YAAY,IAAM,EAAK,IAAK,MAAO,GAEjD,GAAM,CAAE,aAAc,EAEtB,OACE,EAAM,SAAW,EAAU,IAAI,KAAK,GACpC,EAAM,UAAY,EAAU,IAAI,MAAM,GACtC,EAAM,UAAY,EAAU,IAAI,MAAM,GACtC,EAAM,WAAa,EAAU,IAAI,OAAO,CAE5C,CASA,SAAgB,SAAS,EAAsB,EAAiB,EAA0B,aAAa,EAAY,CACjH,IAAM,EAAO,UAAU,EAAS,CAAM,EAEtC,OAAO,IAAS,MAAQ,UAAU,EAAO,CAAI,CAC/C"}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,9 +1,4 @@
|
|
|
1
1
|
import type { ShortcutStep } from './parser';
|
|
2
|
-
export type BindingEntry = {
|
|
3
|
-
readonly shortcut: readonly ShortcutStep[];
|
|
4
|
-
readonly trigger: 'keydown' | 'keyup';
|
|
5
|
-
};
|
|
6
|
-
export type Handler = (event: KeyboardEvent) => void;
|
|
7
2
|
/**
|
|
8
3
|
* Guard function for fine-grained binding context.
|
|
9
4
|
*
|
|
@@ -20,59 +15,73 @@ export type Handler = (event: KeyboardEvent) => void;
|
|
|
20
15
|
* { when: (e) => !isModalOpen() }
|
|
21
16
|
*
|
|
22
17
|
* // Per-binding: only fire when event target is the specific panel
|
|
23
|
-
* { '
|
|
18
|
+
* { id: 'close-panel', shortcut: 'escape', handler: closePanel, when: (e) => e.target === panel }
|
|
24
19
|
*
|
|
25
20
|
* Both conditions must be met for the handler to execute.
|
|
26
21
|
*/
|
|
27
22
|
export type When = (event: KeyboardEvent) => boolean;
|
|
28
|
-
export type
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
23
|
+
export type Handler = (event: KeyboardEvent) => void;
|
|
24
|
+
export type KeymapEvent = {
|
|
25
|
+
readonly target: EventTarget;
|
|
26
|
+
readonly trigger: 'keydown' | 'keyup';
|
|
27
|
+
readonly type: 'chord-cancel';
|
|
28
|
+
} | {
|
|
29
|
+
readonly step: ShortcutStep;
|
|
30
|
+
readonly target: EventTarget;
|
|
31
|
+
readonly trigger: 'keydown' | 'keyup';
|
|
32
|
+
readonly type: 'chord-start';
|
|
33
|
+
} | {
|
|
34
|
+
readonly steps: readonly ShortcutStep[];
|
|
35
|
+
readonly target: EventTarget;
|
|
36
|
+
readonly trigger: 'keydown' | 'keyup';
|
|
37
|
+
readonly type: 'chord-progress';
|
|
38
|
+
} | {
|
|
39
|
+
readonly target: EventTarget;
|
|
40
|
+
readonly trigger: 'keydown' | 'keyup';
|
|
41
|
+
readonly type: 'chord-timeout';
|
|
42
|
+
} | {
|
|
43
|
+
readonly binding: BindingEntry;
|
|
44
|
+
readonly target: EventTarget;
|
|
45
|
+
readonly trigger: 'keydown' | 'keyup';
|
|
46
|
+
readonly type: 'match';
|
|
47
|
+
} | {
|
|
48
|
+
readonly type: 'dispose';
|
|
32
49
|
};
|
|
33
|
-
export type BindingValue = Handler | BindingOptions;
|
|
34
50
|
/**
|
|
35
|
-
*
|
|
51
|
+
* A single ordered binding.
|
|
36
52
|
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
53
|
+
* Each binding has an explicit `id` (string) so duplicate shortcuts can coexist
|
|
54
|
+
* with different ids — `unbind(id)` removes by id, not by shortcut string.
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* const map = createKeymap([
|
|
58
|
+
* { id: 'save', shortcut: 'mod+s', handler: save },
|
|
59
|
+
* { id: 'palette', shortcut: 'mod+shift+p', handler: openPalette },
|
|
60
|
+
* { id: 'top', shortcut: 'g g', handler: goToTop },
|
|
61
|
+
* { id: 'close', shortcut: 'escape', handler: closePanel, when: (e) => !isEditableTarget(e.target) },
|
|
62
|
+
* { id: 'play', shortcut: 'space', handler: togglePlay, trigger: 'keyup' },
|
|
63
|
+
* ], { modKey: 'ctrl' });
|
|
40
64
|
*/
|
|
41
|
-
export
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
65
|
+
export interface Binding {
|
|
66
|
+
/** Handler invoked when the shortcut matches. */
|
|
67
|
+
handler: Handler;
|
|
68
|
+
/** Stable identifier for this binding. Used by `unbind(id)`. */
|
|
69
|
+
id: string;
|
|
70
|
+
/** Call `event.preventDefault()` when matched. Defaults to `true`. */
|
|
71
|
+
preventDefault?: boolean;
|
|
72
|
+
/** Shortcut string, e.g. `'mod+s'` or `'g g'`. */
|
|
73
|
+
shortcut: string;
|
|
74
|
+
/** Call `event.stopPropagation()` when matched. Defaults to `false`. */
|
|
75
|
+
stopPropagation?: boolean;
|
|
76
|
+
/** Event phase. Defaults to `'keydown'`. */
|
|
77
|
+
trigger?: 'keydown' | 'keyup';
|
|
78
|
+
/** Per-binding guard. Both global and per-binding guards must pass. */
|
|
79
|
+
when?: When;
|
|
80
|
+
}
|
|
56
81
|
export interface KeymapOptions {
|
|
82
|
+
/** Milliseconds to wait for the next step of a chord before the partial chord expires. Defaults to 1000. Must be a positive finite number; `createKeymap` throws `KeymapConfigError` otherwise. */
|
|
57
83
|
chordTimeout?: number;
|
|
58
84
|
modKey?: 'ctrl' | 'meta';
|
|
59
|
-
/**
|
|
60
|
-
* Optional callback to observe chord state changes.
|
|
61
|
-
*
|
|
62
|
-
* Fires when a chord starts, progresses through steps, completes, or times out.
|
|
63
|
-
* Useful for debugging, logging, testing, or implementing chord UI hints.
|
|
64
|
-
*
|
|
65
|
-
* @example
|
|
66
|
-
* {
|
|
67
|
-
* onChordState: (change) => {
|
|
68
|
-
* if (change.type === 'started') console.log('Chord started:', change.step.key);
|
|
69
|
-
* if (change.type === 'timeout') console.log('Chord timed out');
|
|
70
|
-
* }
|
|
71
|
-
* }
|
|
72
|
-
*/
|
|
73
|
-
onChordState?: (change: ChordStateChange) => void;
|
|
74
|
-
preventDefault?: boolean;
|
|
75
|
-
stopPropagation?: boolean;
|
|
76
85
|
/**
|
|
77
86
|
* Guard function for all bindings in this keymap.
|
|
78
87
|
*
|
|
@@ -85,13 +94,25 @@ export interface KeymapOptions {
|
|
|
85
94
|
when?: When;
|
|
86
95
|
}
|
|
87
96
|
export interface Keymap {
|
|
88
|
-
|
|
97
|
+
/** Adds a binding (replacing any existing binding with the same id) and returns an unbind closure. */
|
|
98
|
+
bind(binding: Binding): () => void;
|
|
89
99
|
readonly disposalSignal: AbortSignal;
|
|
90
100
|
dispose(): void;
|
|
91
101
|
readonly disposed: boolean;
|
|
92
102
|
listBindings(): readonly BindingEntry[];
|
|
93
103
|
mount(target: EventTarget): () => void;
|
|
94
|
-
|
|
104
|
+
tap(handler: (event: KeymapEvent) => void, options?: {
|
|
105
|
+
signal?: AbortSignal;
|
|
106
|
+
}): () => void;
|
|
107
|
+
/** Removes the binding with the given id. Warns in development when unknown. */
|
|
108
|
+
unbind(id: string): void;
|
|
95
109
|
[Symbol.dispose](): void;
|
|
96
110
|
}
|
|
111
|
+
export type BindingEntry = {
|
|
112
|
+
readonly id: string;
|
|
113
|
+
readonly shortcut: readonly ShortcutStep[];
|
|
114
|
+
readonly trigger: 'keydown' | 'keyup';
|
|
115
|
+
readonly preventDefault: boolean;
|
|
116
|
+
readonly stopPropagation: boolean;
|
|
117
|
+
};
|
|
97
118
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAE7C,MAAM,MAAM,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vielzeug/keymap",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "Headless keyboard shortcut manager with chord sequences
|
|
3
|
+
"version": "26.10.0",
|
|
4
|
+
"description": "Headless keyboard shortcut manager with chord sequences",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "https://github.com/helmuthdu/vielzeug",
|
|
@@ -22,6 +22,18 @@
|
|
|
22
22
|
"import": "./dist/index.js",
|
|
23
23
|
"require": "./dist/index.cjs",
|
|
24
24
|
"types": "./dist/index.d.ts"
|
|
25
|
+
},
|
|
26
|
+
"./parse": {
|
|
27
|
+
"import": "./dist/parse.js",
|
|
28
|
+
"require": "./dist/parse.cjs",
|
|
29
|
+
"types": "./dist/parse.d.ts"
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"typesVersions": {
|
|
33
|
+
"*": {
|
|
34
|
+
"parse": [
|
|
35
|
+
"dist/parse.d.ts"
|
|
36
|
+
]
|
|
25
37
|
}
|
|
26
38
|
},
|
|
27
39
|
"sideEffects": false,
|
|
@@ -30,18 +42,18 @@
|
|
|
30
42
|
"registry": "https://registry.npmjs.org/"
|
|
31
43
|
},
|
|
32
44
|
"scripts": {
|
|
33
|
-
"build": "vite build && pnpm run build:bundle && pnpm run build:types",
|
|
45
|
+
"build": "vite build && pnpm --silent run build:bundle && pnpm --silent run build:types",
|
|
34
46
|
"build:bundle": "vite build --config vite.bundle.config.ts",
|
|
35
47
|
"build:types": "tsc -p tsconfig.declarations.json",
|
|
36
48
|
"fix": "biome check --write src",
|
|
37
49
|
"lint": "biome ci src",
|
|
38
|
-
"prepublishOnly": "pnpm run build",
|
|
50
|
+
"prepublishOnly": "pnpm --silent run build",
|
|
39
51
|
"test": "vitest"
|
|
40
52
|
},
|
|
41
53
|
"devDependencies": {
|
|
42
|
-
"@types/node": "^26.2
|
|
54
|
+
"@types/node": "^26.6.2",
|
|
43
55
|
"typescript": "^6.0.3",
|
|
44
|
-
"vite": "^8.
|
|
45
|
-
"vitest": "^
|
|
56
|
+
"vite": "^8.3.0",
|
|
57
|
+
"vitest": "^5.0.1"
|
|
46
58
|
}
|
|
47
59
|
}
|