Skip to content

Commit 7142783

Browse files
committed
fix: #436 Ctrl+Click (Cmd+Click) not working on Mac
1 parent f2b21c1 commit 7142783

File tree

4 files changed

+47
-29
lines changed

4 files changed

+47
-29
lines changed

src/lib/components/modes/treemode/JSONNode.svelte

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@
7272
import ValidationErrorIcon from './ValidationErrorIcon.svelte'
7373
import { isObject } from '$lib/utils/typeUtils.js'
7474
import { classnames } from '$lib/utils/cssUtils.js'
75+
import { isCtrlKeyDown } from 'svelte-jsoneditor/utils/keyBindings'
7576
7677
export let value: unknown
7778
export let path: JSONPath
@@ -216,7 +217,7 @@
216217
function toggleExpand(event: MouseEvent) {
217218
event.stopPropagation()
218219
219-
const recursive = event.ctrlKey
220+
const recursive = isCtrlKeyDown(event)
220221
context.onExpand(path, !expanded, recursive)
221222
}
222223

src/lib/plugins/value/components/ReadonlyValue.svelte

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
ValueNormalization
1414
} from '$lib/types.js'
1515
import type { JSONPath } from 'immutable-json-patch'
16+
import { isCtrlKeyDown } from 'svelte-jsoneditor/utils/keyBindings'
1617
1718
export let path: JSONPath
1819
export let value: unknown
@@ -26,7 +27,7 @@
2627
$: valueIsUrl = isUrl(value)
2728
2829
function handleValueClick(event: MouseEvent) {
29-
if (typeof value === 'string' && valueIsUrl && event.ctrlKey) {
30+
if (typeof value === 'string' && valueIsUrl && isCtrlKeyDown(event)) {
3031
event.preventDefault()
3132
event.stopPropagation()
3233

src/lib/utils/keyBindings.test.ts

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,26 +8,34 @@ describe('keyBindings', () => {
88
const altKey = true
99
const metaKey = true
1010

11+
const defaults = { ctrlKey: false, shiftKey: false, altKey: false, metaKey: false }
12+
1113
test('keyComboFromEvent', () => {
12-
strictEqual(keyComboFromEvent({ key: 'a' }), 'A')
13-
strictEqual(keyComboFromEvent({ key: 'A' }), 'A')
14-
strictEqual(keyComboFromEvent({ key: '=' }), '=')
15-
strictEqual(keyComboFromEvent({ shiftKey, key: '+' }), 'Shift++')
16-
strictEqual(keyComboFromEvent({ altKey, key: '=' }), 'Alt+=')
17-
strictEqual(keyComboFromEvent({ key: '-' }), '-')
18-
strictEqual(keyComboFromEvent({ shiftKey, key: '-' }), 'Shift+-')
19-
strictEqual(keyComboFromEvent({ ctrlKey, key: 'a' }), 'Ctrl+A')
20-
strictEqual(keyComboFromEvent({ metaKey, key: 'a' }), 'Ctrl+A')
21-
strictEqual(keyComboFromEvent({ shiftKey, key: 'a' }), 'Shift+A')
22-
strictEqual(keyComboFromEvent({ ctrlKey, shiftKey, key: 'a' }), 'Ctrl+Shift+A')
23-
strictEqual(keyComboFromEvent({ key: 'Control' }), '') // does not happen in practice
24-
strictEqual(keyComboFromEvent({ ctrlKey, key: 'Control' }), 'Ctrl')
14+
strictEqual(keyComboFromEvent({ ...defaults, key: 'a' }), 'A')
15+
strictEqual(keyComboFromEvent({ ...defaults, key: 'A' }), 'A')
16+
strictEqual(keyComboFromEvent({ ...defaults, key: '=' }), '=')
17+
strictEqual(keyComboFromEvent({ ...defaults, shiftKey, key: '+' }), 'Shift++')
18+
strictEqual(keyComboFromEvent({ ...defaults, altKey, key: '=' }), 'Alt+=')
19+
strictEqual(keyComboFromEvent({ ...defaults, key: '-' }), '-')
20+
strictEqual(keyComboFromEvent({ ...defaults, shiftKey, key: '-' }), 'Shift+-')
21+
strictEqual(keyComboFromEvent({ ...defaults, ctrlKey, key: 'a' }), 'Ctrl+A')
22+
strictEqual(
23+
keyComboFromEvent({ ...defaults, metaKey, key: 'a' }, '+', () => true),
24+
'Ctrl+A'
25+
)
26+
strictEqual(keyComboFromEvent({ ...defaults, shiftKey, key: 'a' }), 'Shift+A')
27+
strictEqual(keyComboFromEvent({ ...defaults, ctrlKey, shiftKey, key: 'a' }), 'Ctrl+Shift+A')
28+
strictEqual(keyComboFromEvent({ ...defaults, key: 'Control' }), '') // does not happen in practice
29+
strictEqual(keyComboFromEvent({ ...defaults, ctrlKey, key: 'Control' }), 'Ctrl')
2530
})
2631

2732
test('keyComboFromEvent with custom separator', () => {
2833
const separator = '///'
29-
strictEqual(keyComboFromEvent({ key: 'a' }, separator), 'A')
30-
strictEqual(keyComboFromEvent({ ctrlKey, key: 'a' }, separator), 'Ctrl///A')
31-
strictEqual(keyComboFromEvent({ ctrlKey, shiftKey, key: 'A' }, separator), 'Ctrl///Shift///A')
34+
strictEqual(keyComboFromEvent({ ...defaults, key: 'a' }, separator), 'A')
35+
strictEqual(keyComboFromEvent({ ...defaults, ctrlKey, key: 'a' }, separator), 'Ctrl///A')
36+
strictEqual(
37+
keyComboFromEvent({ ...defaults, ctrlKey, shiftKey, key: 'A' }, separator),
38+
'Ctrl///Shift///A'
39+
)
3240
})
3341
})

src/lib/utils/keyBindings.ts

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
// inspiration: https://github.com/andrepolischuk/keycomb
22

3+
import { isMac as _isMac } from './navigatorUtils.js'
4+
35
// KeyComboEvent is a subset of KeyboardEvent
46
export interface KeyComboEvent {
5-
ctrlKey?: boolean
6-
metaKey?: boolean
7-
altKey?: boolean
8-
shiftKey?: boolean
7+
ctrlKey: boolean
8+
metaKey: boolean
9+
altKey: boolean
10+
shiftKey: boolean
911
key: string
1012
}
1113

@@ -17,15 +19,10 @@ export interface KeyComboEvent {
1719
* meta keys "Ctrl" ("Command" on Mac), and "Alt" ("Alt" or "Option" on Mac)
1820
* So pressing "Command" and "A"on Mac will return "Ctrl+A"
1921
*/
20-
export function keyComboFromEvent(event: KeyComboEvent, separator = '+'): string {
22+
export function keyComboFromEvent(event: KeyComboEvent, separator = '+', isMac = _isMac): string {
2123
const combi = []
2224

23-
if (event.ctrlKey) {
24-
// Control on Windows
25-
combi.push('Ctrl')
26-
}
27-
if (event.metaKey) {
28-
// Command on Mac
25+
if (isCtrlKeyDown(event, isMac)) {
2926
combi.push('Ctrl')
3027
}
3128
if (event.altKey) {
@@ -45,6 +42,17 @@ export function keyComboFromEvent(event: KeyComboEvent, separator = '+'): string
4542
return combi.join(separator)
4643
}
4744

45+
/**
46+
* Test whether the Ctrl key (windows, linux) or Command key (mac) is down
47+
*/
48+
export function isCtrlKeyDown(
49+
event: { ctrlKey: boolean; metaKey: boolean },
50+
isMac = _isMac
51+
): boolean {
52+
// metaKey is the Command key ⌘ on a Mac (but the Windows Key ⊞ on Windows)
53+
return event.ctrlKey || (event.metaKey && isMac())
54+
}
55+
4856
const metaKeys = {
4957
Ctrl: true,
5058
Command: true,

0 commit comments

Comments
 (0)