@dxos/keyboard 0.3.10-main.560f82b → 0.3.10-main.dcfebef
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/dist/lib/browser/index.mjs +21 -27
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node/index.cjs +21 -27
- package/dist/lib/node/index.cjs.map +3 -3
- package/dist/lib/node/meta.json +1 -1
- package/dist/types/src/keyboard.d.ts +2 -4
- package/dist/types/src/keyboard.d.ts.map +1 -1
- package/package.json +6 -6
- package/src/keyboard.stories.tsx +1 -1
- package/src/keyboard.ts +24 -30
|
@@ -10,12 +10,6 @@ import {
|
|
|
10
10
|
// packages/common/keyboard/src/keyboard.ts
|
|
11
11
|
import { invariant } from "@dxos/invariant";
|
|
12
12
|
var __dxlog_file = "/home/runner/work/dxos/dxos/packages/common/keyboard/src/keyboard.ts";
|
|
13
|
-
var modifiers = [
|
|
14
|
-
"alt",
|
|
15
|
-
"ctrl",
|
|
16
|
-
"shift",
|
|
17
|
-
"meta"
|
|
18
|
-
];
|
|
19
13
|
var KeyboardContext = class {
|
|
20
14
|
constructor() {
|
|
21
15
|
this._keyMap = /* @__PURE__ */ new Map();
|
|
@@ -29,10 +23,15 @@ var KeyboardContext = class {
|
|
|
29
23
|
bind(config) {
|
|
30
24
|
const { binding } = config;
|
|
31
25
|
const parts = binding.split("+");
|
|
32
|
-
const mods = parts.filter((key) =>
|
|
26
|
+
const mods = parts.filter((key) => [
|
|
27
|
+
"alt",
|
|
28
|
+
"ctrl",
|
|
29
|
+
"meta",
|
|
30
|
+
"shift"
|
|
31
|
+
].includes(key)).sort();
|
|
33
32
|
invariant(mods.length === 0 || mods.length === parts.length - 1, void 0, {
|
|
34
33
|
F: __dxlog_file,
|
|
35
|
-
L:
|
|
34
|
+
L: 36,
|
|
36
35
|
S: this,
|
|
37
36
|
A: [
|
|
38
37
|
"mods.length === 0 || mods.length === parts.length - 1",
|
|
@@ -78,22 +77,9 @@ var Keyboard = class _Keyboard {
|
|
|
78
77
|
destroy() {
|
|
79
78
|
document.removeEventListener("keydown", this._keyHandler);
|
|
80
79
|
}
|
|
81
|
-
|
|
80
|
+
setContext(path = ROOT) {
|
|
82
81
|
this._path = path;
|
|
83
82
|
}
|
|
84
|
-
getCurrentContext() {
|
|
85
|
-
return this._path;
|
|
86
|
-
}
|
|
87
|
-
getContext(path = ROOT) {
|
|
88
|
-
let context = this._keyMap.get(path);
|
|
89
|
-
if (!context) {
|
|
90
|
-
context = new KeyboardContext();
|
|
91
|
-
this._keyMap.set(path, context);
|
|
92
|
-
this._contexts.push(path);
|
|
93
|
-
this._contexts.sort();
|
|
94
|
-
}
|
|
95
|
-
return context;
|
|
96
|
-
}
|
|
97
83
|
getBindings() {
|
|
98
84
|
const bindings = /* @__PURE__ */ new Map();
|
|
99
85
|
for (let i = 0; i < this._contexts.length; ++i) {
|
|
@@ -106,23 +92,31 @@ var Keyboard = class _Keyboard {
|
|
|
106
92
|
}
|
|
107
93
|
return Array.from(bindings.values());
|
|
108
94
|
}
|
|
95
|
+
getContext(path = ROOT) {
|
|
96
|
+
let context = this._keyMap.get(path);
|
|
97
|
+
if (!context) {
|
|
98
|
+
context = new KeyboardContext();
|
|
99
|
+
this._keyMap.set(path, context);
|
|
100
|
+
this._contexts.push(path);
|
|
101
|
+
this._contexts.sort();
|
|
102
|
+
}
|
|
103
|
+
return context;
|
|
104
|
+
}
|
|
109
105
|
handleKeyDown(event) {
|
|
110
106
|
const { altKey, ctrlKey, metaKey, shiftKey, key } = event;
|
|
111
107
|
if (key !== "Alt" && key !== "Control" && key !== "Meta" && key !== "Shift") {
|
|
112
|
-
const tagName = event.target?.tagName;
|
|
113
|
-
const isInput = tagName === "INPUT" || tagName === "TEXTAREA" || event.target?.getAttribute("contenteditable");
|
|
114
108
|
const str = [
|
|
115
109
|
altKey && "alt",
|
|
116
110
|
ctrlKey && "ctrl",
|
|
117
|
-
shiftKey && "shift",
|
|
118
111
|
metaKey && "meta",
|
|
112
|
+
shiftKey && "shift",
|
|
119
113
|
key
|
|
120
114
|
].filter(Boolean).join("+");
|
|
121
115
|
for (let i = this._contexts.length - 1; i >= 0; --i) {
|
|
122
116
|
const path = this._contexts[i];
|
|
123
117
|
if (this._path.startsWith(path)) {
|
|
124
|
-
const { data, handler
|
|
125
|
-
if (handler
|
|
118
|
+
const { data, handler } = this.getContext(path).get(str) ?? {};
|
|
119
|
+
if (handler) {
|
|
126
120
|
const result = handler({
|
|
127
121
|
context: path,
|
|
128
122
|
binding: str,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/keyboard.ts", "../../../src/util.ts"],
|
|
4
|
-
"sourcesContent": ["//\n// Copyright 2023 DXOS.org\n//\n\nimport { invariant } from '@dxos/invariant';\n\nexport type KeyHandler = (props: {\n context: string;\n binding: string;\n data?: any;\n event: KeyboardEvent;\n}) => boolean | void;\n\nexport type KeyBinding = {\n binding: string;\n handler: KeyHandler;\n
|
|
5
|
-
"mappings": ";;;;;;;;;;AAIA,SAASA,iBAAiB;;
|
|
6
|
-
"names": ["invariant", "
|
|
4
|
+
"sourcesContent": ["//\n// Copyright 2023 DXOS.org\n//\n\nimport { invariant } from '@dxos/invariant';\n\nexport type KeyHandler = (props: {\n context: string;\n binding: string;\n data?: any;\n event: KeyboardEvent;\n}) => boolean | void;\n\nexport type KeyBinding = {\n binding: string;\n handler: KeyHandler;\n data?: any;\n};\n\nclass KeyboardContext {\n readonly _keyMap = new Map<string, KeyBinding>();\n\n get bindings() {\n return Array.from(this._keyMap.values());\n }\n\n get(binding: string) {\n return this._keyMap.get(binding);\n }\n\n bind(config: KeyBinding) {\n // Normalize order of modifiers.\n const { binding } = config;\n const parts = binding.split('+');\n const mods = parts.filter((key) => ['alt', 'ctrl', 'meta', 'shift'].includes(key)).sort();\n invariant(mods.length === 0 || mods.length === parts.length - 1);\n if (mods.length) {\n config.binding = [...mods, parts[parts.length - 1]].join('+');\n }\n\n // console.log('bind', config);\n this._keyMap.set(config.binding, config);\n }\n\n unbind(binding: string) {\n this._keyMap.delete(binding);\n }\n}\n\nconst ROOT = '';\n\n/**\n * Manages context-aware key bindings.\n */\nexport class Keyboard {\n static singleton = new Keyboard();\n\n private readonly _root = new KeyboardContext();\n private readonly _keyMap = new Map<string, KeyboardContext>([[ROOT, this._root]]);\n private readonly _contexts: string[] = [ROOT];\n private readonly _keyHandler = this.handleKeyDown.bind(this);\n private _path = ROOT;\n\n initialize() {\n document.addEventListener('keydown', this._keyHandler);\n }\n\n destroy() {\n document.removeEventListener('keydown', this._keyHandler);\n }\n\n bind = this._root.bind.bind(this._root);\n unbind = this._root.unbind.bind(this._root);\n\n setContext(path = ROOT) {\n this._path = path;\n }\n\n getBindings() {\n const bindings = new Map<string, KeyBinding>();\n for (let i = 0; i < this._contexts.length; ++i) {\n const path = this._contexts[i];\n if (this._path.startsWith(path)) {\n this.getContext(path).bindings.forEach((binding) => {\n bindings.set(binding.binding, binding);\n });\n }\n }\n\n return Array.from(bindings.values());\n }\n\n getContext(path = ROOT): KeyboardContext {\n let context = this._keyMap.get(path);\n if (!context) {\n context = new KeyboardContext();\n this._keyMap.set(path, context);\n this._contexts.push(path);\n this._contexts.sort();\n }\n\n return context;\n }\n\n handleKeyDown(event: KeyboardEvent) {\n const { altKey, ctrlKey, metaKey, shiftKey, key } = event;\n\n if (key !== 'Alt' && key !== 'Control' && key !== 'Meta' && key !== 'Shift') {\n // TODO(burdon): Option to call anywhere.\n // TODO(burdon): Check for contenteditable.\n // const tagName = (event.target as any)?.tagName;\n // if (tagName === 'INPUT' || tagName === 'TEXTAREA') {\n // return;\n // }\n\n const str = [altKey && 'alt', ctrlKey && 'ctrl', metaKey && 'meta', shiftKey && 'shift', key]\n .filter(Boolean)\n .join('+');\n\n // Scan matching contexts.\n for (let i = this._contexts.length - 1; i >= 0; --i) {\n const path = this._contexts[i];\n if (this._path.startsWith(path)) {\n const { data, handler } = this.getContext(path).get(str) ?? {};\n // console.log('>>>', path, str, handler);\n if (handler) {\n const result = handler({ context: path, binding: str, data, event });\n if (result !== false) {\n // TODO(burdon): Doesn't prevent actions in markdown editor.\n event.preventDefault();\n event.stopPropagation();\n }\n\n return;\n }\n }\n }\n }\n }\n}\n", "//\n// Copyright 2023 DXOS.org\n//\n\n// https://www.w3.org/TR/DOM-Level-3-Events/#events-keyboardevents\n// https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key\n// https://support.apple.com/en-us/HT201236\n// https://support.apple.com/guide/mac-help/what-are-those-symbols-shown-in-menus-cpmh0011/mac\n\n// TODO(burdon): Show Mac/Windows/Linux variants.\nconst symbols: Record<string, string> = {\n // Mods.\n ctrl: '⌃',\n shift: '⇧',\n alt: '⌥',\n meta: '⌘',\n\n // Special keys.\n Backspace: '⌫',\n Enter: '⏎',\n Escape: '⎋',\n Space: '␣',\n Tab: '⇥',\n};\n\nexport const keySymbols = (keyBinding: string): string[] => {\n const parts = keyBinding.split('+');\n return parts.map((part) => symbols[part] ?? part.toUpperCase());\n};\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;AAIA,SAASA,iBAAiB;;AAe1B,IAAMC,kBAAN,MAAMA;EAAN;AACWC,mBAAU,oBAAIC,IAAAA;;EAEvB,IAAIC,WAAW;AACb,WAAOC,MAAMC,KAAK,KAAKJ,QAAQK,OAAM,CAAA;EACvC;EAEAC,IAAIC,SAAiB;AACnB,WAAO,KAAKP,QAAQM,IAAIC,OAAAA;EAC1B;EAEAC,KAAKC,QAAoB;AAEvB,UAAM,EAAEF,QAAO,IAAKE;AACpB,UAAMC,QAAQH,QAAQI,MAAM,GAAA;AAC5B,UAAMC,OAAOF,MAAMG,OAAO,CAACC,QAAQ;MAAC;MAAO;MAAQ;MAAQ;MAASC,SAASD,GAAAA,CAAAA,EAAME,KAAI;AACvFlB,cAAUc,KAAKK,WAAW,KAAKL,KAAKK,WAAWP,MAAMO,SAAS,GAAA,QAAA;;;;;;;;;AAC9D,QAAIL,KAAKK,QAAQ;AACfR,aAAOF,UAAU;WAAIK;QAAMF,MAAMA,MAAMO,SAAS,CAAA;QAAIC,KAAK,GAAA;IAC3D;AAGA,SAAKlB,QAAQmB,IAAIV,OAAOF,SAASE,MAAAA;EACnC;EAEAW,OAAOb,SAAiB;AACtB,SAAKP,QAAQqB,OAAOd,OAAAA;EACtB;AACF;AAEA,IAAMe,OAAO;AAKN,IAAMC,WAAN,MAAMA,UAAAA;EAAN;AAGYC,iBAAQ,IAAIzB,gBAAAA;AACZC,mBAAU,oBAAIC,IAA6B;MAAC;QAACqB;QAAM,KAAKE;;KAAO;AAC/DC,qBAAsB;MAACH;;AACvBI,uBAAc,KAAKC,cAAcnB,KAAK,IAAI;AACnDoB,iBAAQN;AAUhBd,gBAAO,KAAKgB,MAAMhB,KAAKA,KAAK,KAAKgB,KAAK;AACtCJ,kBAAS,KAAKI,MAAMJ,OAAOZ,KAAK,KAAKgB,KAAK;;EAjB1C;SAAOK,YAAY,IAAIN,UAAAA;;EAQvBO,aAAa;AACXC,aAASC,iBAAiB,WAAW,KAAKN,WAAW;EACvD;EAEAO,UAAU;AACRF,aAASG,oBAAoB,WAAW,KAAKR,WAAW;EAC1D;EAKAS,WAAWC,OAAOd,MAAM;AACtB,SAAKM,QAAQQ;EACf;EAEAC,cAAc;AACZ,UAAMnC,WAAW,oBAAID,IAAAA;AACrB,aAASqC,IAAI,GAAGA,IAAI,KAAKb,UAAUR,QAAQ,EAAEqB,GAAG;AAC9C,YAAMF,OAAO,KAAKX,UAAUa,CAAAA;AAC5B,UAAI,KAAKV,MAAMW,WAAWH,IAAAA,GAAO;AAC/B,aAAKI,WAAWJ,IAAAA,EAAMlC,SAASuC,QAAQ,CAAClC,YAAAA;AACtCL,mBAASiB,IAAIZ,QAAQA,SAASA,OAAAA;QAChC,CAAA;MACF;IACF;AAEA,WAAOJ,MAAMC,KAAKF,SAASG,OAAM,CAAA;EACnC;EAEAmC,WAAWJ,OAAOd,MAAuB;AACvC,QAAIoB,UAAU,KAAK1C,QAAQM,IAAI8B,IAAAA;AAC/B,QAAI,CAACM,SAAS;AACZA,gBAAU,IAAI3C,gBAAAA;AACd,WAAKC,QAAQmB,IAAIiB,MAAMM,OAAAA;AACvB,WAAKjB,UAAUkB,KAAKP,IAAAA;AACpB,WAAKX,UAAUT,KAAI;IACrB;AAEA,WAAO0B;EACT;EAEAf,cAAciB,OAAsB;AAClC,UAAM,EAAEC,QAAQC,SAASC,SAASC,UAAUlC,IAAG,IAAK8B;AAEpD,QAAI9B,QAAQ,SAASA,QAAQ,aAAaA,QAAQ,UAAUA,QAAQ,SAAS;AAQ3E,YAAMmC,MAAM;QAACJ,UAAU;QAAOC,WAAW;QAAQC,WAAW;QAAQC,YAAY;QAASlC;QACtFD,OAAOqC,OAAAA,EACPhC,KAAK,GAAA;AAGR,eAASoB,IAAI,KAAKb,UAAUR,SAAS,GAAGqB,KAAK,GAAG,EAAEA,GAAG;AACnD,cAAMF,OAAO,KAAKX,UAAUa,CAAAA;AAC5B,YAAI,KAAKV,MAAMW,WAAWH,IAAAA,GAAO;AAC/B,gBAAM,EAAEe,MAAMC,QAAO,IAAK,KAAKZ,WAAWJ,IAAAA,EAAM9B,IAAI2C,GAAAA,KAAQ,CAAC;AAE7D,cAAIG,SAAS;AACX,kBAAMC,SAASD,QAAQ;cAAEV,SAASN;cAAM7B,SAAS0C;cAAKE;cAAMP;YAAM,CAAA;AAClE,gBAAIS,WAAW,OAAO;AAEpBT,oBAAMU,eAAc;AACpBV,oBAAMW,gBAAe;YACvB;AAEA;UACF;QACF;MACF;IACF;EACF;AACF;;;ACjIA,IAAMC,UAAkC;;EAEtCC,MAAM;EACNC,OAAO;EACPC,KAAK;EACLC,MAAM;;EAGNC,WAAW;EACXC,OAAO;EACPC,QAAQ;EACRC,OAAO;EACPC,KAAK;AACP;AAEO,IAAMC,aAAa,CAACC,eAAAA;AACzB,QAAMC,QAAQD,WAAWE,MAAM,GAAA;AAC/B,SAAOD,MAAME,IAAI,CAACC,SAASf,QAAQe,IAAAA,KAASA,KAAKC,YAAW,CAAA;AAC9D;",
|
|
6
|
+
"names": ["invariant", "KeyboardContext", "_keyMap", "Map", "bindings", "Array", "from", "values", "get", "binding", "bind", "config", "parts", "split", "mods", "filter", "key", "includes", "sort", "length", "join", "set", "unbind", "delete", "ROOT", "Keyboard", "_root", "_contexts", "_keyHandler", "handleKeyDown", "_path", "singleton", "initialize", "document", "addEventListener", "destroy", "removeEventListener", "setContext", "path", "getBindings", "i", "startsWith", "getContext", "forEach", "context", "push", "event", "altKey", "ctrlKey", "metaKey", "shiftKey", "str", "Boolean", "data", "handler", "result", "preventDefault", "stopPropagation", "symbols", "ctrl", "shift", "alt", "meta", "Backspace", "Enter", "Escape", "Space", "Tab", "keySymbols", "keyBinding", "parts", "split", "map", "part", "toUpperCase"]
|
|
7
7
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"inputs":{"inject-globals:@inject-globals":{"bytes":384,"imports":[{"path":"@dxos/node-std/inject-globals","kind":"import-statement","external":true}],"format":"esm"},"packages/common/keyboard/src/keyboard.ts":{"bytes":
|
|
1
|
+
{"inputs":{"inject-globals:@inject-globals":{"bytes":384,"imports":[{"path":"@dxos/node-std/inject-globals","kind":"import-statement","external":true}],"format":"esm"},"packages/common/keyboard/src/keyboard.ts":{"bytes":14347,"imports":[{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"@inject-globals","kind":"import-statement","external":true}],"format":"esm"},"packages/common/keyboard/src/util.ts":{"bytes":2733,"imports":[{"path":"@inject-globals","kind":"import-statement","external":true}],"format":"esm"},"packages/common/keyboard/src/index.ts":{"bytes":544,"imports":[{"path":"packages/common/keyboard/src/keyboard.ts","kind":"import-statement","original":"./keyboard"},{"path":"packages/common/keyboard/src/util.ts","kind":"import-statement","original":"./util"},{"path":"@inject-globals","kind":"import-statement","external":true}],"format":"esm"}},"outputs":{"packages/common/keyboard/dist/lib/browser/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":8209},"packages/common/keyboard/dist/lib/browser/index.mjs":{"imports":[{"path":"@dxos/node-std/inject-globals","kind":"import-statement","external":true},{"path":"@dxos/invariant","kind":"import-statement","external":true}],"exports":["Keyboard","keySymbols"],"entryPoint":"packages/common/keyboard/src/index.ts","inputs":{"inject-globals:@inject-globals":{"bytesInOutput":79},"packages/common/keyboard/src/keyboard.ts":{"bytesInOutput":3316},"packages/common/keyboard/src/index.ts":{"bytesInOutput":0},"packages/common/keyboard/src/util.ts":{"bytesInOutput":362}},"bytes":3983}}}
|
package/dist/lib/node/index.cjs
CHANGED
|
@@ -24,12 +24,6 @@ __export(node_exports, {
|
|
|
24
24
|
module.exports = __toCommonJS(node_exports);
|
|
25
25
|
var import_invariant = require("@dxos/invariant");
|
|
26
26
|
var __dxlog_file = "/home/runner/work/dxos/dxos/packages/common/keyboard/src/keyboard.ts";
|
|
27
|
-
var modifiers = [
|
|
28
|
-
"alt",
|
|
29
|
-
"ctrl",
|
|
30
|
-
"shift",
|
|
31
|
-
"meta"
|
|
32
|
-
];
|
|
33
27
|
var KeyboardContext = class {
|
|
34
28
|
constructor() {
|
|
35
29
|
this._keyMap = /* @__PURE__ */ new Map();
|
|
@@ -43,10 +37,15 @@ var KeyboardContext = class {
|
|
|
43
37
|
bind(config) {
|
|
44
38
|
const { binding } = config;
|
|
45
39
|
const parts = binding.split("+");
|
|
46
|
-
const mods = parts.filter((key) =>
|
|
40
|
+
const mods = parts.filter((key) => [
|
|
41
|
+
"alt",
|
|
42
|
+
"ctrl",
|
|
43
|
+
"meta",
|
|
44
|
+
"shift"
|
|
45
|
+
].includes(key)).sort();
|
|
47
46
|
(0, import_invariant.invariant)(mods.length === 0 || mods.length === parts.length - 1, void 0, {
|
|
48
47
|
F: __dxlog_file,
|
|
49
|
-
L:
|
|
48
|
+
L: 36,
|
|
50
49
|
S: this,
|
|
51
50
|
A: [
|
|
52
51
|
"mods.length === 0 || mods.length === parts.length - 1",
|
|
@@ -92,22 +91,9 @@ var Keyboard = class _Keyboard {
|
|
|
92
91
|
destroy() {
|
|
93
92
|
document.removeEventListener("keydown", this._keyHandler);
|
|
94
93
|
}
|
|
95
|
-
|
|
94
|
+
setContext(path = ROOT) {
|
|
96
95
|
this._path = path;
|
|
97
96
|
}
|
|
98
|
-
getCurrentContext() {
|
|
99
|
-
return this._path;
|
|
100
|
-
}
|
|
101
|
-
getContext(path = ROOT) {
|
|
102
|
-
let context = this._keyMap.get(path);
|
|
103
|
-
if (!context) {
|
|
104
|
-
context = new KeyboardContext();
|
|
105
|
-
this._keyMap.set(path, context);
|
|
106
|
-
this._contexts.push(path);
|
|
107
|
-
this._contexts.sort();
|
|
108
|
-
}
|
|
109
|
-
return context;
|
|
110
|
-
}
|
|
111
97
|
getBindings() {
|
|
112
98
|
const bindings = /* @__PURE__ */ new Map();
|
|
113
99
|
for (let i = 0; i < this._contexts.length; ++i) {
|
|
@@ -120,23 +106,31 @@ var Keyboard = class _Keyboard {
|
|
|
120
106
|
}
|
|
121
107
|
return Array.from(bindings.values());
|
|
122
108
|
}
|
|
109
|
+
getContext(path = ROOT) {
|
|
110
|
+
let context = this._keyMap.get(path);
|
|
111
|
+
if (!context) {
|
|
112
|
+
context = new KeyboardContext();
|
|
113
|
+
this._keyMap.set(path, context);
|
|
114
|
+
this._contexts.push(path);
|
|
115
|
+
this._contexts.sort();
|
|
116
|
+
}
|
|
117
|
+
return context;
|
|
118
|
+
}
|
|
123
119
|
handleKeyDown(event) {
|
|
124
120
|
const { altKey, ctrlKey, metaKey, shiftKey, key } = event;
|
|
125
121
|
if (key !== "Alt" && key !== "Control" && key !== "Meta" && key !== "Shift") {
|
|
126
|
-
const tagName = event.target?.tagName;
|
|
127
|
-
const isInput = tagName === "INPUT" || tagName === "TEXTAREA" || event.target?.getAttribute("contenteditable");
|
|
128
122
|
const str = [
|
|
129
123
|
altKey && "alt",
|
|
130
124
|
ctrlKey && "ctrl",
|
|
131
|
-
shiftKey && "shift",
|
|
132
125
|
metaKey && "meta",
|
|
126
|
+
shiftKey && "shift",
|
|
133
127
|
key
|
|
134
128
|
].filter(Boolean).join("+");
|
|
135
129
|
for (let i = this._contexts.length - 1; i >= 0; --i) {
|
|
136
130
|
const path = this._contexts[i];
|
|
137
131
|
if (this._path.startsWith(path)) {
|
|
138
|
-
const { data, handler
|
|
139
|
-
if (handler
|
|
132
|
+
const { data, handler } = this.getContext(path).get(str) ?? {};
|
|
133
|
+
if (handler) {
|
|
140
134
|
const result = handler({
|
|
141
135
|
context: path,
|
|
142
136
|
binding: str,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/keyboard.ts", "../../../src/util.ts"],
|
|
4
|
-
"sourcesContent": ["//\n// Copyright 2023 DXOS.org\n//\n\nimport { invariant } from '@dxos/invariant';\n\nexport type KeyHandler = (props: {\n context: string;\n binding: string;\n data?: any;\n event: KeyboardEvent;\n}) => boolean | void;\n\nexport type KeyBinding = {\n binding: string;\n handler: KeyHandler;\n
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;AAIA,uBAA0B;;
|
|
6
|
-
"names": ["
|
|
4
|
+
"sourcesContent": ["//\n// Copyright 2023 DXOS.org\n//\n\nimport { invariant } from '@dxos/invariant';\n\nexport type KeyHandler = (props: {\n context: string;\n binding: string;\n data?: any;\n event: KeyboardEvent;\n}) => boolean | void;\n\nexport type KeyBinding = {\n binding: string;\n handler: KeyHandler;\n data?: any;\n};\n\nclass KeyboardContext {\n readonly _keyMap = new Map<string, KeyBinding>();\n\n get bindings() {\n return Array.from(this._keyMap.values());\n }\n\n get(binding: string) {\n return this._keyMap.get(binding);\n }\n\n bind(config: KeyBinding) {\n // Normalize order of modifiers.\n const { binding } = config;\n const parts = binding.split('+');\n const mods = parts.filter((key) => ['alt', 'ctrl', 'meta', 'shift'].includes(key)).sort();\n invariant(mods.length === 0 || mods.length === parts.length - 1);\n if (mods.length) {\n config.binding = [...mods, parts[parts.length - 1]].join('+');\n }\n\n // console.log('bind', config);\n this._keyMap.set(config.binding, config);\n }\n\n unbind(binding: string) {\n this._keyMap.delete(binding);\n }\n}\n\nconst ROOT = '';\n\n/**\n * Manages context-aware key bindings.\n */\nexport class Keyboard {\n static singleton = new Keyboard();\n\n private readonly _root = new KeyboardContext();\n private readonly _keyMap = new Map<string, KeyboardContext>([[ROOT, this._root]]);\n private readonly _contexts: string[] = [ROOT];\n private readonly _keyHandler = this.handleKeyDown.bind(this);\n private _path = ROOT;\n\n initialize() {\n document.addEventListener('keydown', this._keyHandler);\n }\n\n destroy() {\n document.removeEventListener('keydown', this._keyHandler);\n }\n\n bind = this._root.bind.bind(this._root);\n unbind = this._root.unbind.bind(this._root);\n\n setContext(path = ROOT) {\n this._path = path;\n }\n\n getBindings() {\n const bindings = new Map<string, KeyBinding>();\n for (let i = 0; i < this._contexts.length; ++i) {\n const path = this._contexts[i];\n if (this._path.startsWith(path)) {\n this.getContext(path).bindings.forEach((binding) => {\n bindings.set(binding.binding, binding);\n });\n }\n }\n\n return Array.from(bindings.values());\n }\n\n getContext(path = ROOT): KeyboardContext {\n let context = this._keyMap.get(path);\n if (!context) {\n context = new KeyboardContext();\n this._keyMap.set(path, context);\n this._contexts.push(path);\n this._contexts.sort();\n }\n\n return context;\n }\n\n handleKeyDown(event: KeyboardEvent) {\n const { altKey, ctrlKey, metaKey, shiftKey, key } = event;\n\n if (key !== 'Alt' && key !== 'Control' && key !== 'Meta' && key !== 'Shift') {\n // TODO(burdon): Option to call anywhere.\n // TODO(burdon): Check for contenteditable.\n // const tagName = (event.target as any)?.tagName;\n // if (tagName === 'INPUT' || tagName === 'TEXTAREA') {\n // return;\n // }\n\n const str = [altKey && 'alt', ctrlKey && 'ctrl', metaKey && 'meta', shiftKey && 'shift', key]\n .filter(Boolean)\n .join('+');\n\n // Scan matching contexts.\n for (let i = this._contexts.length - 1; i >= 0; --i) {\n const path = this._contexts[i];\n if (this._path.startsWith(path)) {\n const { data, handler } = this.getContext(path).get(str) ?? {};\n // console.log('>>>', path, str, handler);\n if (handler) {\n const result = handler({ context: path, binding: str, data, event });\n if (result !== false) {\n // TODO(burdon): Doesn't prevent actions in markdown editor.\n event.preventDefault();\n event.stopPropagation();\n }\n\n return;\n }\n }\n }\n }\n }\n}\n", "//\n// Copyright 2023 DXOS.org\n//\n\n// https://www.w3.org/TR/DOM-Level-3-Events/#events-keyboardevents\n// https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key\n// https://support.apple.com/en-us/HT201236\n// https://support.apple.com/guide/mac-help/what-are-those-symbols-shown-in-menus-cpmh0011/mac\n\n// TODO(burdon): Show Mac/Windows/Linux variants.\nconst symbols: Record<string, string> = {\n // Mods.\n ctrl: '⌃',\n shift: '⇧',\n alt: '⌥',\n meta: '⌘',\n\n // Special keys.\n Backspace: '⌫',\n Enter: '⏎',\n Escape: '⎋',\n Space: '␣',\n Tab: '⇥',\n};\n\nexport const keySymbols = (keyBinding: string): string[] => {\n const parts = keyBinding.split('+');\n return parts.map((part) => symbols[part] ?? part.toUpperCase());\n};\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["KeyboardContext", "_keyMap", "Map", "bindings", "Array", "from", "values", "get", "binding", "bind", "config", "parts", "split", "mods", "filter", "key", "includes", "sort", "invariant", "length", "join", "set", "unbind", "delete", "ROOT", "Keyboard", "_root", "_contexts", "_keyHandler", "handleKeyDown", "_path", "singleton", "initialize", "document", "addEventListener", "destroy", "removeEventListener", "setContext", "path", "getBindings", "i", "startsWith", "getContext", "forEach", "context", "push", "event", "altKey", "ctrlKey", "metaKey", "shiftKey", "str", "Boolean", "data", "handler", "result", "preventDefault", "stopPropagation", "symbols", "ctrl", "shift", "alt", "meta", "Backspace", "Enter", "Escape", "Space", "Tab", "keySymbols", "keyBinding", "map", "part", "toUpperCase"]
|
|
7
7
|
}
|
package/dist/lib/node/meta.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"inputs":{"packages/common/keyboard/src/keyboard.ts":{"bytes":
|
|
1
|
+
{"inputs":{"packages/common/keyboard/src/keyboard.ts":{"bytes":14347,"imports":[{"path":"@dxos/invariant","kind":"import-statement","external":true}],"format":"esm"},"packages/common/keyboard/src/util.ts":{"bytes":2733,"imports":[],"format":"esm"},"packages/common/keyboard/src/index.ts":{"bytes":544,"imports":[{"path":"packages/common/keyboard/src/keyboard.ts","kind":"import-statement","original":"./keyboard"},{"path":"packages/common/keyboard/src/util.ts","kind":"import-statement","original":"./util"}],"format":"esm"}},"outputs":{"packages/common/keyboard/dist/lib/node/index.cjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":8200},"packages/common/keyboard/dist/lib/node/index.cjs":{"imports":[{"path":"@dxos/invariant","kind":"import-statement","external":true}],"exports":["Keyboard","keySymbols"],"entryPoint":"packages/common/keyboard/src/index.ts","inputs":{"packages/common/keyboard/src/keyboard.ts":{"bytesInOutput":3316},"packages/common/keyboard/src/index.ts":{"bytesInOutput":0},"packages/common/keyboard/src/util.ts":{"bytesInOutput":362}},"bytes":3835}}}
|
|
@@ -7,7 +7,6 @@ export type KeyHandler = (props: {
|
|
|
7
7
|
export type KeyBinding = {
|
|
8
8
|
binding: string;
|
|
9
9
|
handler: KeyHandler;
|
|
10
|
-
disableInput?: boolean;
|
|
11
10
|
data?: any;
|
|
12
11
|
};
|
|
13
12
|
declare class KeyboardContext {
|
|
@@ -31,10 +30,9 @@ export declare class Keyboard {
|
|
|
31
30
|
destroy(): void;
|
|
32
31
|
bind: (config: KeyBinding) => void;
|
|
33
32
|
unbind: (binding: string) => void;
|
|
34
|
-
|
|
35
|
-
getCurrentContext(): string;
|
|
36
|
-
getContext(path?: string): KeyboardContext;
|
|
33
|
+
setContext(path?: string): void;
|
|
37
34
|
getBindings(): KeyBinding[];
|
|
35
|
+
getContext(path?: string): KeyboardContext;
|
|
38
36
|
handleKeyDown(event: KeyboardEvent): void;
|
|
39
37
|
}
|
|
40
38
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keyboard.d.ts","sourceRoot":"","sources":["../../../src/keyboard.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,UAAU,GAAG,CAAC,KAAK,EAAE;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,KAAK,EAAE,aAAa,CAAC;CACtB,KAAK,OAAO,GAAG,IAAI,CAAC;AAErB,MAAM,MAAM,UAAU,GAAG;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,UAAU,CAAC;IACpB,
|
|
1
|
+
{"version":3,"file":"keyboard.d.ts","sourceRoot":"","sources":["../../../src/keyboard.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,UAAU,GAAG,CAAC,KAAK,EAAE;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,KAAK,EAAE,aAAa,CAAC;CACtB,KAAK,OAAO,GAAG,IAAI,CAAC;AAErB,MAAM,MAAM,UAAU,GAAG;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,UAAU,CAAC;IACpB,IAAI,CAAC,EAAE,GAAG,CAAC;CACZ,CAAC;AAEF,cAAM,eAAe;IACnB,QAAQ,CAAC,OAAO,0BAAiC;IAEjD,IAAI,QAAQ,iBAEX;IAED,GAAG,CAAC,OAAO,EAAE,MAAM;IAInB,IAAI,CAAC,MAAM,EAAE,UAAU;IAcvB,MAAM,CAAC,OAAO,EAAE,MAAM;CAGvB;AAID;;GAEG;AACH,qBAAa,QAAQ;IACnB,MAAM,CAAC,SAAS,WAAkB;IAElC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAyB;IAC/C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA0D;IAClF,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAoB;IAC9C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAiC;IAC7D,OAAO,CAAC,KAAK,CAAQ;IAErB,UAAU;IAIV,OAAO;IAIP,IAAI,+BAAoC;IACxC,MAAM,4BAAsC;IAE5C,UAAU,CAAC,IAAI,SAAO;IAItB,WAAW;IAcX,UAAU,CAAC,IAAI,SAAO,GAAG,eAAe;IAYxC,aAAa,CAAC,KAAK,EAAE,aAAa;CAmCnC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/keyboard",
|
|
3
|
-
"version": "0.3.10-main.
|
|
3
|
+
"version": "0.3.10-main.dcfebef",
|
|
4
4
|
"description": "Keyboard bindings",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -16,15 +16,15 @@
|
|
|
16
16
|
"src"
|
|
17
17
|
],
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@dxos/
|
|
20
|
-
"@dxos/
|
|
19
|
+
"@dxos/invariant": "0.3.10-main.dcfebef",
|
|
20
|
+
"@dxos/node-std": "0.3.10-main.dcfebef"
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
|
23
23
|
"react": "^18.2.0",
|
|
24
24
|
"react-dom": "^18.2.0",
|
|
25
|
-
"@dxos/react-ui": "0.3.10-main.
|
|
26
|
-
"@dxos/react-ui-theme": "0.3.10-main.
|
|
27
|
-
"@dxos/storybook-utils": "0.3.10-main.
|
|
25
|
+
"@dxos/react-ui": "0.3.10-main.dcfebef",
|
|
26
|
+
"@dxos/react-ui-theme": "0.3.10-main.dcfebef",
|
|
27
|
+
"@dxos/storybook-utils": "0.3.10-main.dcfebef"
|
|
28
28
|
},
|
|
29
29
|
"publishConfig": {
|
|
30
30
|
"access": "public"
|
package/src/keyboard.stories.tsx
CHANGED
package/src/keyboard.ts
CHANGED
|
@@ -14,12 +14,9 @@ export type KeyHandler = (props: {
|
|
|
14
14
|
export type KeyBinding = {
|
|
15
15
|
binding: string;
|
|
16
16
|
handler: KeyHandler;
|
|
17
|
-
disableInput?: boolean;
|
|
18
17
|
data?: any;
|
|
19
18
|
};
|
|
20
19
|
|
|
21
|
-
const modifiers = ['alt', 'ctrl', 'shift', 'meta'];
|
|
22
|
-
|
|
23
20
|
class KeyboardContext {
|
|
24
21
|
readonly _keyMap = new Map<string, KeyBinding>();
|
|
25
22
|
|
|
@@ -35,7 +32,7 @@ class KeyboardContext {
|
|
|
35
32
|
// Normalize order of modifiers.
|
|
36
33
|
const { binding } = config;
|
|
37
34
|
const parts = binding.split('+');
|
|
38
|
-
const mods = parts.filter((key) =>
|
|
35
|
+
const mods = parts.filter((key) => ['alt', 'ctrl', 'meta', 'shift'].includes(key)).sort();
|
|
39
36
|
invariant(mods.length === 0 || mods.length === parts.length - 1);
|
|
40
37
|
if (mods.length) {
|
|
41
38
|
config.binding = [...mods, parts[parts.length - 1]].join('+');
|
|
@@ -75,26 +72,10 @@ export class Keyboard {
|
|
|
75
72
|
bind = this._root.bind.bind(this._root);
|
|
76
73
|
unbind = this._root.unbind.bind(this._root);
|
|
77
74
|
|
|
78
|
-
|
|
75
|
+
setContext(path = ROOT) {
|
|
79
76
|
this._path = path;
|
|
80
77
|
}
|
|
81
78
|
|
|
82
|
-
getCurrentContext() {
|
|
83
|
-
return this._path;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
getContext(path = ROOT): KeyboardContext {
|
|
87
|
-
let context = this._keyMap.get(path);
|
|
88
|
-
if (!context) {
|
|
89
|
-
context = new KeyboardContext();
|
|
90
|
-
this._keyMap.set(path, context);
|
|
91
|
-
this._contexts.push(path);
|
|
92
|
-
this._contexts.sort();
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
return context;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
79
|
getBindings() {
|
|
99
80
|
const bindings = new Map<string, KeyBinding>();
|
|
100
81
|
for (let i = 0; i < this._contexts.length; ++i) {
|
|
@@ -109,17 +90,30 @@ export class Keyboard {
|
|
|
109
90
|
return Array.from(bindings.values());
|
|
110
91
|
}
|
|
111
92
|
|
|
93
|
+
getContext(path = ROOT): KeyboardContext {
|
|
94
|
+
let context = this._keyMap.get(path);
|
|
95
|
+
if (!context) {
|
|
96
|
+
context = new KeyboardContext();
|
|
97
|
+
this._keyMap.set(path, context);
|
|
98
|
+
this._contexts.push(path);
|
|
99
|
+
this._contexts.sort();
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return context;
|
|
103
|
+
}
|
|
104
|
+
|
|
112
105
|
handleKeyDown(event: KeyboardEvent) {
|
|
113
106
|
const { altKey, ctrlKey, metaKey, shiftKey, key } = event;
|
|
114
107
|
|
|
115
108
|
if (key !== 'Alt' && key !== 'Control' && key !== 'Meta' && key !== 'Shift') {
|
|
116
|
-
//
|
|
117
|
-
|
|
118
|
-
const
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
//
|
|
122
|
-
|
|
109
|
+
// TODO(burdon): Option to call anywhere.
|
|
110
|
+
// TODO(burdon): Check for contenteditable.
|
|
111
|
+
// const tagName = (event.target as any)?.tagName;
|
|
112
|
+
// if (tagName === 'INPUT' || tagName === 'TEXTAREA') {
|
|
113
|
+
// return;
|
|
114
|
+
// }
|
|
115
|
+
|
|
116
|
+
const str = [altKey && 'alt', ctrlKey && 'ctrl', metaKey && 'meta', shiftKey && 'shift', key]
|
|
123
117
|
.filter(Boolean)
|
|
124
118
|
.join('+');
|
|
125
119
|
|
|
@@ -127,9 +121,9 @@ export class Keyboard {
|
|
|
127
121
|
for (let i = this._contexts.length - 1; i >= 0; --i) {
|
|
128
122
|
const path = this._contexts[i];
|
|
129
123
|
if (this._path.startsWith(path)) {
|
|
130
|
-
const { data, handler
|
|
124
|
+
const { data, handler } = this.getContext(path).get(str) ?? {};
|
|
131
125
|
// console.log('>>>', path, str, handler);
|
|
132
|
-
if (handler
|
|
126
|
+
if (handler) {
|
|
133
127
|
const result = handler({ context: path, binding: str, data, event });
|
|
134
128
|
if (result !== false) {
|
|
135
129
|
// TODO(burdon): Doesn't prevent actions in markdown editor.
|