@prosekit/core 0.8.6 → 0.8.7

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,7 +1,7 @@
1
1
  {
2
2
  "name": "@prosekit/core",
3
3
  "type": "module",
4
- "version": "0.8.6",
4
+ "version": "0.8.7",
5
5
  "private": false,
6
6
  "description": "Core features for ProseKit",
7
7
  "author": {
@@ -52,11 +52,12 @@
52
52
  "devDependencies": {
53
53
  "@types/diffable-html": "^5.0.2",
54
54
  "diffable-html": "^6.0.1",
55
- "tsdown": "^0.16.2",
55
+ "tsdown": "^0.16.5",
56
56
  "typescript": "~5.9.3",
57
- "vitest": "^4.0.8",
58
- "@prosekit/config-vitest": "0.0.0",
59
- "@prosekit/config-tsdown": "0.0.0"
57
+ "vitest": "^4.0.10",
58
+ "vitest-browser-commands": "^0.2.0",
59
+ "@prosekit/config-tsdown": "0.0.0",
60
+ "@prosekit/config-vitest": "0.0.0"
60
61
  },
61
62
  "publishConfig": {
62
63
  "dev": {}
@@ -5,10 +5,17 @@ import {
5
5
  it,
6
6
  vi,
7
7
  } from 'vitest'
8
+ import { keyboard } from 'vitest-browser-commands/playwright'
8
9
 
9
10
  import { union } from '../editor/union'
10
11
  import { withPriority } from '../editor/with-priority'
11
- import { setupTest } from '../testing'
12
+ import {
13
+ defineDoc,
14
+ defineParagraph,
15
+ defineText,
16
+ setupTest,
17
+ setupTestFromExtension,
18
+ } from '../testing'
12
19
  import { Priority } from '../types/priority'
13
20
 
14
21
  import {
@@ -122,4 +129,66 @@ describe('keymap', () => {
122
129
  // Highest priority should be called first
123
130
  expect(callOrder).toEqual(['highest', 'default', 'lowest'])
124
131
  })
132
+
133
+ it('can merge keybindings with different variants', async () => {
134
+ const called: string[] = []
135
+ const { editor } = setupTestFromExtension(union(
136
+ defineDoc(),
137
+ defineText(),
138
+ defineParagraph(),
139
+ ))
140
+
141
+ const record = (label: string): Command => {
142
+ return () => {
143
+ called.push(label)
144
+ return false
145
+ }
146
+ }
147
+
148
+ const keybindings = [
149
+ // Match Ctrl-b
150
+ 'ctrl-b',
151
+ 'CTRL-b',
152
+
153
+ // Match Ctrl-Shift-b
154
+ 'c-B',
155
+ 'ctrl-shift-b',
156
+ 'c-s-B',
157
+ 'Ctrl-B',
158
+
159
+ // Do not match
160
+ 'ctrl-c',
161
+ ]
162
+ const keymap: Keymap = Object.fromEntries(keybindings.map(binding => [binding, record(binding)]))
163
+
164
+ editor.use(defineKeymap(keymap))
165
+
166
+ called.length = 0
167
+ await keyboard.down('Control')
168
+ await keyboard.down('b')
169
+ await keyboard.up('b')
170
+ await keyboard.up('Control')
171
+ expect(called).toMatchInlineSnapshot(`
172
+ [
173
+ "ctrl-b",
174
+ "CTRL-b",
175
+ ]
176
+ `)
177
+
178
+ called.length = 0
179
+ await keyboard.down('Control')
180
+ await keyboard.down('Shift')
181
+ await keyboard.down('B')
182
+ await keyboard.up('B')
183
+ await keyboard.up('Shift')
184
+ await keyboard.up('Control')
185
+ expect(called).toMatchInlineSnapshot(`
186
+ [
187
+ "c-s-B",
188
+ "c-B",
189
+ "Ctrl-B",
190
+ "ctrl-shift-b",
191
+ ]
192
+ `)
193
+ })
125
194
  })
@@ -15,6 +15,7 @@ import {
15
15
  import { defineFacetPayload } from '../facets/facet-extension'
16
16
  import type { PlainExtension } from '../types/extension'
17
17
  import { toReversed } from '../utils/array'
18
+ import { isApple } from '../utils/env'
18
19
 
19
20
  import {
20
21
  pluginFacet,
@@ -22,6 +23,9 @@ import {
22
23
  } from './plugin'
23
24
 
24
25
  /**
26
+ * A set of keybindings. Please read the
27
+ * [documentation](https://prosemirror.net/docs/ref/#keymap) for more details.
28
+ *
25
29
  * @public
26
30
  */
27
31
  export interface Keymap {
@@ -29,6 +33,9 @@ export interface Keymap {
29
33
  }
30
34
 
31
35
  /**
36
+ * Adds a set of keybindings to the editor. Please read the
37
+ * [documentation](https://prosemirror.net/docs/ref/#keymap) for more details.
38
+ *
32
39
  * @public
33
40
  */
34
41
  export function defineKeymap(keymap: Keymap): PlainExtension {
@@ -81,7 +88,8 @@ function mergeKeymaps(keymaps: Keymap[]): Keymap {
81
88
 
82
89
  for (const keymap of keymaps) {
83
90
  for (const [key, command] of Object.entries(keymap)) {
84
- const commands = bindings[key] || (bindings[key] = [])
91
+ const normalizedKey = normalizeKeyName(key)
92
+ const commands = bindings[normalizedKey] ||= []
85
93
  commands.push(command)
86
94
  }
87
95
  }
@@ -93,4 +101,27 @@ function mergeCommands(commands: Command[]): Command {
93
101
  return chainCommands(...commands)
94
102
  }
95
103
 
104
+ // Copied from https://github.com/ProseMirror/prosemirror-keymap/blob/1.2.3/src/keymap.ts#L8
105
+ function normalizeKeyName(name: string) {
106
+ let parts = name.split(/-(?!$)/), result = parts[parts.length - 1]
107
+ if (result == 'Space') result = ' '
108
+ let alt, ctrl, shift, meta
109
+ for (let i = 0; i < parts.length - 1; i++) {
110
+ let mod = parts[i]
111
+ if (/^(cmd|meta|m)$/i.test(mod)) meta = true
112
+ else if (/^a(lt)?$/i.test(mod)) alt = true
113
+ else if (/^(c|ctrl|control)$/i.test(mod)) ctrl = true
114
+ else if (/^s(hift)?$/i.test(mod)) shift = true
115
+ else if (/^mod$/i.test(mod)) {
116
+ if (isApple) meta = true
117
+ else ctrl = true
118
+ } else throw new Error('Unrecognized modifier name: ' + mod)
119
+ }
120
+ if (alt) result = 'Alt-' + result
121
+ if (ctrl) result = 'Ctrl-' + result
122
+ if (meta) result = 'Meta-' + result
123
+ if (shift) result = 'Shift-' + result
124
+ return result
125
+ }
126
+
96
127
  const keymapPluginKey = new PluginKey('prosekit-keymap')
package/src/utils/env.ts CHANGED
@@ -1,4 +1,6 @@
1
1
  /**
2
+ * https://github.com/ProseMirror/prosemirror-keymap/blob/1.2.3/src/keymap.ts#L5
3
+ *
2
4
  * @internal
3
5
  */
4
6
  export const isApple: boolean = typeof navigator !== 'undefined'