/
keymap.ts
120 lines (113 loc) · 4.1 KB
/
keymap.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
/* eslint-disable import/no-extraneous-dependencies */
import {
wrapIn, setBlockType, chainCommands, toggleMark, exitCode,
joinUp, joinDown, lift, selectParentNode,
} from 'prosemirror-commands';
import {
wrapInList, splitListItem, liftListItem, sinkListItem,
} from 'prosemirror-schema-list';
import { undo, redo } from 'prosemirror-history';
import { undoInputRule } from 'prosemirror-inputrules';
import { Command } from 'prosemirror-state';
import { Schema } from 'prosemirror-model';
const mac = typeof navigator !== 'undefined' ? /Mac|iP(hone|[oa]d)/.test(navigator.platform) : false;
/// Inspect the given schema looking for marks and nodes from the
/// basic schema, and if found, add key bindings related to them.
/// This will add:
///
/// * **Mod-b** for toggling [strong](#schema-basic.StrongMark)
/// * **Mod-i** for toggling [emphasis](#schema-basic.EmMark)
/// * **Mod-`** for toggling [code font](#schema-basic.CodeMark)
/// * **Ctrl-Shift-0** for making the current textblock a paragraph
/// * **Ctrl-Shift-1** to **Ctrl-Shift-Digit6** for making the current
/// textblock a heading of the corresponding level
/// * **Ctrl-Shift-Backslash** to make the current textblock a code block
/// * **Ctrl-Shift-8** to wrap the selection in an ordered list
/// * **Ctrl-Shift-9** to wrap the selection in a bullet list
/// * **Ctrl->** to wrap the selection in a block quote
/// * **Enter** to split a non-empty textblock in a list item while at
/// the same time splitting the list item
/// * **Mod-Enter** to insert a hard break
/// * **Mod-_** to insert a horizontal rule
/// * **Backspace** to undo an input rule
/// * **Alt-ArrowUp** to `joinUp`
/// * **Alt-ArrowDown** to `joinDown`
/// * **Mod-BracketLeft** to `lift`
/// * **Escape** to `selectParentNode`
///
/// You can suppress or map these bindings by passing a `mapKeys`
/// argument, which maps key names (say `"Mod-B"` to either `false`, to
/// remove the binding, or a new key name string.
export function buildKeymap(schema: Schema, mapKeys?: { [key: string]: false | string }) {
const keys: { [key: string]: Command } = {}; let
type;
function bind(key: string, cmd: Command) {
let keyname = key;
if (mapKeys) {
const mapped = mapKeys[key];
if (mapped === false) return;
if (mapped) keyname = mapped;
}
keys[keyname] = cmd;
}
bind('Mod-z', undo);
bind('Shift-Mod-z', redo);
bind('Backspace', undoInputRule);
if (!mac) bind('Mod-y', redo);
bind('Alt-ArrowUp', joinUp);
bind('Alt-ArrowDown', joinDown);
bind('Mod-BracketLeft', lift);
bind('Escape', selectParentNode);
if (schema.marks.strong) {
type = schema.marks.strong;
bind('Mod-b', toggleMark(type));
bind('Mod-B', toggleMark(type));
}
if (schema.marks.em) {
type = schema.marks.em;
bind('Mod-i', toggleMark(type));
bind('Mod-I', toggleMark(type));
}
if (schema.nodes.bullet_list) {
type = schema.nodes.bullet_list;
bind('Shift-Ctrl-8', wrapInList(type));
}
if (schema.nodes.ordered_list) {
type = schema.nodes.ordered_list;
bind('Shift-Ctrl-9', wrapInList(type));
}
if (schema.nodes.blockquote) {
type = schema.nodes.blockquote;
bind('Ctrl->', wrapIn(type));
}
if (schema.nodes.hard_break) {
type = schema.nodes.hard_break;
const br = type; const
cmd = chainCommands(exitCode, (state, dispatch) => {
if (dispatch) dispatch(state.tr.replaceSelectionWith(br.create()).scrollIntoView());
return true;
});
bind('Mod-Enter', cmd);
bind('Shift-Enter', cmd);
if (mac) bind('Ctrl-Enter', cmd);
}
if (schema.nodes.list_item) {
type = schema.nodes.list_item;
bind('Enter', splitListItem(type));
bind('Mod-[', liftListItem(type));
bind('Mod-]', sinkListItem(type));
}
if (schema.nodes.paragraph) {
type = schema.nodes.paragraph;
bind('Shift-Ctrl-0', setBlockType(type));
}
if (schema.nodes.horizontal_rule) {
type = schema.nodes.horizontal_rule;
const hr = type;
bind('Mod-_', (state, dispatch) => {
if (dispatch) dispatch(state.tr.replaceSelectionWith(hr.create()).scrollIntoView());
return true;
});
}
return keys;
}