@dxos/keyboard 0.9.1-main.c7dcc2e112 → 0.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dxos/keyboard",
3
- "version": "0.9.1-main.c7dcc2e112",
3
+ "version": "0.10.0",
4
4
  "description": "Keyboard bindings",
5
5
  "homepage": "https://dxos.org",
6
6
  "bugs": "https://github.com/dxos/dxos/issues",
@@ -26,16 +26,16 @@
26
26
  "src"
27
27
  ],
28
28
  "dependencies": {
29
- "@dxos/node-std": "0.9.1-main.c7dcc2e112",
30
- "@dxos/invariant": "0.9.1-main.c7dcc2e112",
31
- "@dxos/util": "0.9.1-main.c7dcc2e112"
29
+ "@dxos/invariant": "0.10.0",
30
+ "@dxos/node-std": "0.10.0",
31
+ "@dxos/util": "0.10.0"
32
32
  },
33
33
  "devDependencies": {
34
- "react": "~19.2.3",
35
- "react-dom": "~19.2.3",
36
- "@dxos/storybook-utils": "0.9.1-main.c7dcc2e112",
37
- "@dxos/react-ui": "0.9.1-main.c7dcc2e112",
38
- "@dxos/ui-theme": "0.9.1-main.c7dcc2e112"
34
+ "react": "~19.2.7",
35
+ "react-dom": "~19.2.7",
36
+ "@dxos/storybook-utils": "0.10.0",
37
+ "@dxos/react-ui": "0.10.0",
38
+ "@dxos/ui-theme": "0.10.0"
39
39
  },
40
40
  "publishConfig": {
41
41
  "access": "public"
@@ -8,7 +8,7 @@ import React, { useEffect, useState } from 'react';
8
8
  import { Input, Select } from '@dxos/react-ui';
9
9
  import { withTheme } from '@dxos/react-ui/testing';
10
10
 
11
- import { type KeyHandler, Keyboard } from './keyboard';
11
+ import { Keyboard, type KeyHandler } from './keyboard';
12
12
 
13
13
  const contexts = ['/', '/space/1', '/space/2', '/space/2/a', '/space/2/b'];
14
14
 
@@ -2,14 +2,41 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import { describe, expect, test } from 'vitest';
5
+ import { describe, expect, test, vi } from 'vitest';
6
6
 
7
- import { Keyboard } from './keyboard';
7
+ import { Keyboard, nestKeyboardContext } from './keyboard';
8
8
 
9
9
  describe('keyboard', () => {
10
- test('should pass', () => {
10
+ test('binds shortcuts on the active context', () => {
11
11
  const keyboard = new Keyboard();
12
12
  keyboard.bind({ shortcut: 'meta+k', handler: () => true });
13
13
  expect(keyboard.getBindings()).to.have.length(1);
14
14
  });
15
+
16
+ test('child context inherits root bindings', async () => {
17
+ const keyboard = new Keyboard();
18
+ const handler = vi.fn();
19
+ keyboard.getContext('root').bind({ shortcut: 'shift+meta+f', handler });
20
+ keyboard.setCurrentContext('root/plank-1');
21
+
22
+ await keyboard.handleKeyDown({
23
+ altKey: false,
24
+ ctrlKey: false,
25
+ metaKey: true,
26
+ shiftKey: true,
27
+ key: 'F',
28
+ preventDefault: vi.fn(),
29
+ stopPropagation: vi.fn(),
30
+ } as unknown as KeyboardEvent);
31
+
32
+ expect(handler).toHaveBeenCalledOnce();
33
+ });
34
+
35
+ test('nestKeyboardContext nests attendable ids under graph root', ({ expect }) => {
36
+ expect(nestKeyboardContext(undefined)).to.equal('root');
37
+ expect(nestKeyboardContext('')).to.equal('root');
38
+ expect(nestKeyboardContext('root')).to.equal('root');
39
+ expect(nestKeyboardContext('plank-1')).to.equal('root/plank-1');
40
+ expect(nestKeyboardContext('root/plank-1')).to.equal('root/plank-1');
41
+ });
15
42
  });
package/src/keyboard.ts CHANGED
@@ -57,6 +57,20 @@ class KeyboardContext {
57
57
 
58
58
  const ROOT = '';
59
59
 
60
+ /** Graph root segment; matches `@dxos/plugin-graph` `Node.RootId`. */
61
+ export const GRAPH_ROOT_ID = 'root';
62
+
63
+ /**
64
+ * Nest an attendable segment under the graph root so plank context inherits root-level bindings.
65
+ * An empty/absent segment resolves to the graph root itself.
66
+ */
67
+ export const nestKeyboardContext = (segment?: string): string =>
68
+ segment
69
+ ? segment === GRAPH_ROOT_ID || segment.startsWith(`${GRAPH_ROOT_ID}/`)
70
+ ? segment
71
+ : `${GRAPH_ROOT_ID}/${segment}`
72
+ : GRAPH_ROOT_ID;
73
+
60
74
  /**
61
75
  * Manages context-aware key bindings.
62
76
  */
@@ -123,10 +137,10 @@ export class Keyboard {
123
137
  const isInput =
124
138
  tagName === 'INPUT' || tagName === 'TEXTAREA' || (event.target as any)?.getAttribute('contenteditable');
125
139
 
126
- // Normalized key binding (order matters, see note above).
127
- const str = [ctrlKey && 'ctrl', shiftKey && 'shift', altKey && 'alt', metaKey && 'meta', key]
128
- .filter(Boolean)
129
- .join('+');
140
+ // Normalized key binding (order and case; see parseShortcut).
141
+ const str = parseShortcut(
142
+ [ctrlKey && 'ctrl', shiftKey && 'shift', altKey && 'alt', metaKey && 'meta', key].filter(Boolean).join('+'),
143
+ );
130
144
 
131
145
  // Scan matching contexts.
132
146
  for (let i = this._contexts.length - 1; i >= 0; --i) {