PluginProbe
Code Snippets / 3.10.1
Code Snippets v3.10.1
3.10.2 3.10.1 3.10.0 3.10.0-beta.2 3.10.0-beta.1 4.0.0-beta.1 3.9.6 trunk 2.10.0 2.10.1 2.12.0 2.12.1 2.13.0 2.13.1 2.13.2 2.13.3 2.14.0 2.14.1 2.14.2 2.14.3 2.14.4 2.14.5 2.14.6 3.0.0 3.0.1 All 64 releases
code-snippets / js / components / EditMenu / SnippetForm / fields / CodeEditorShortcuts.tsx

CodeEditorShortcuts.tsx in Code Snippets 3.10.1, at js/components/EditMenu/SnippetForm/fields/CodeEditorShortcuts.tsx

200 lines 6.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import { __, _x } from '@wordpress/i18n'
2 import { getKeyMap } from 'codemirror/src/input/keymap'
3 import React, { Fragment, useMemo } from 'react'
4 import { useSnippetForm } from '../WithSnippetFormContext'
5 import { isMacOS } from '../../../../utils/screen'
6 import type { KeyMap } from 'codemirror'
7
8 const KEYBOARD_KEYS = {
9 'Fn': _x('Fn', 'keyboard key', 'code-snippets'),
10 'Cmd': _x('Ctrl', 'keyboard key', 'code-snippets'),
11 'Ctrl': _x('Ctrl', 'keyboard key', 'code-snippets'),
12 'Shift': _x('Shift', 'keyboard key', 'code-snippets'),
13 'Alt': _x('Alt', 'keyboard key', 'code-snippets'),
14 'Tab': _x('Tab', 'keyboard key', 'code-snippets'),
15 'Up': _x('Up', 'keyboard key', 'code-snippets'),
16 'Down': _x('Down', 'keyboard key', 'code-snippets'),
17 'Left': _x('Left', 'keyboard key', 'code-snippets'),
18 'Right': _x('Right', 'keyboard key', 'code-snippets'),
19 'A': _x('A', 'keyboard key', 'code-snippets'),
20 'B': _x('B', 'keyboard key', 'code-snippets'),
21 'C': _x('C', 'keyboard key', 'code-snippets'),
22 'D': _x('D', 'keyboard key', 'code-snippets'),
23 'E': _x('E', 'keyboard key', 'code-snippets'),
24 'F': _x('F', 'keyboard key', 'code-snippets'),
25 'G': _x('G', 'keyboard key', 'code-snippets'),
26 'H': _x('H', 'keyboard key', 'code-snippets'),
27 'I': _x('I', 'keyboard key', 'code-snippets'),
28 'J': _x('J', 'keyboard key', 'code-snippets'),
29 'K': _x('K', 'keyboard key', 'code-snippets'),
30 'L': _x('L', 'keyboard key', 'code-snippets'),
31 'M': _x('M', 'keyboard key', 'code-snippets'),
32 'N': _x('N', 'keyboard key', 'code-snippets'),
33 'O': _x('O', 'keyboard key', 'code-snippets'),
34 'P': _x('P', 'keyboard key', 'code-snippets'),
35 'Q': _x('Q', 'keyboard key', 'code-snippets'),
36 'R': _x('R', 'keyboard key', 'code-snippets'),
37 'S': _x('S', 'keyboard key', 'code-snippets'),
38 'T': _x('T', 'keyboard key', 'code-snippets'),
39 'U': _x('U', 'keyboard key', 'code-snippets'),
40 'V': _x('V', 'keyboard key', 'code-snippets'),
41 'W': _x('W', 'keyboard key', 'code-snippets'),
42 'X': _x('X', 'keyboard key', 'code-snippets'),
43 'Y': _x('Y', 'keyboard key', 'code-snippets'),
44 'Z': _x('Z', 'keyboard key', 'code-snippets'),
45 '/': _x('/', 'keyboard key', 'code-snippets'),
46 '[': _x(']', 'keyboard key', 'code-snippets'),
47 ']': _x(']', 'keyboard key', 'code-snippets')
48 }
49
50 export const KEYBOARD_SYMBOLS: Partial<typeof KEYBOARD_KEYS> = {
51 Cmd: '',
52 Ctrl: '',
53 Alt: '',
54 Shift: '',
55 Tab: '',
56 Up: '',
57 Down: '',
58 Left: '',
59 Right: ''
60 }
61
62 const keyMapLabels = {
63 saveChanges: __('Save changes', 'code-snippets'),
64 selectAll: __('Select all', 'code-snippets'),
65 find: __('Begin searching', 'code-snippets'),
66 findNext: __('Find next', 'code-snippets'),
67 findPrev: __('Find previous', 'code-snippets'),
68 replace: __('Replace', 'code-snippets'),
69 replaceAll: __('Replace all', 'code-snippets'),
70 findPersistent: __('Persistent search', 'code-snippets'),
71 toggleComment: __('Toggle comment', 'code-snippets'),
72 swapLineUp: __('Swap line up', 'code-snippets'),
73 swapLineDown: __('Swap line down', 'code-snippets'),
74 autoIndent: __('Auto-indent current line or selection', 'code-snippets')
75 }
76
77 const KEY_ORDER: readonly (keyof typeof KEYBOARD_KEYS)[] = isMacOS()
78 ? ['Fn', 'Ctrl', 'Alt', 'Shift', 'Cmd']
79 : ['Cmd', 'Ctrl', 'Shift', 'Alt', 'Fn']
80
81 const getKeyComparisonValue = (key: string): string =>
82 KEY_ORDER.includes(key as keyof typeof KEYBOARD_KEYS)
83 ? String(KEY_ORDER.indexOf(key as keyof typeof KEYBOARD_KEYS))
84 : key
85
86 const unpackKeyMap = (keyMap: KeyMap): Map<string, string[]> => {
87 const result = new Map<string, string[]>()
88
89 for (const [shortcut, action] of Object.entries(keyMap)) {
90 if ('string' === typeof action && keyMapLabels[action as keyof typeof keyMapLabels]) {
91 const keys = shortcut.split('-')
92
93 keys.sort((a, b) =>
94 getKeyComparisonValue(a).localeCompare(getKeyComparisonValue(b)))
95
96 result.set(action, keys)
97 }
98 }
99
100 return result
101 }
102
103 interface KeyboardShortcutMacProps {
104 keys: string[]
105 keyLabels: Partial<Record<string, string>>
106 keySymbols: Partial<Record<string, string>>
107 }
108
109 const KeyboardShortcutMac: React.FC<KeyboardShortcutMacProps> = ({ keys, keyLabels, keySymbols }) =>
110 <span className="keyboard-shortcut mac-keyboard-shortcut">
111 {keys.map(key =>
112 <kbd key={key}>{keySymbols[key] ?? keyLabels[key] ?? key}</kbd>)}
113 </span>
114
115 const SEP = _x('+', 'keyboard shortcut separator', 'code-snippets')
116
117 interface KeyboardShortcutPCProps {
118 keys: string[]
119 keyLabels: Partial<Record<string, string>>
120 }
121
122 const KeyboardShortcutPC: React.FC<KeyboardShortcutPCProps> = ({ keys, keyLabels }) =>
123 <span className="keyboard-shortcut pc-keyboard-shortcot">
124 {keys.map((key, index) =>
125 <Fragment key={key}>
126 <kbd>{keyLabels[key] ?? key}</kbd>
127 {index < keys.length - 1 && <span className="shortcut-separator">{SEP}</span>}
128 </Fragment>)}
129 </span>
130
131 const fallbackKeyMap: Partial<Record<`${string}-${string}`, keyof typeof keyMapLabels>> = {
132 'Ctrl-S': 'saveChanges',
133 'Shift-Tab': 'autoIndent'
134 }
135
136 const fallbackKeyMapMac: typeof fallbackKeyMap = {
137 'Cmd-S': 'saveChanges',
138 'Shift-Tab': 'autoIndent'
139 }
140
141 export interface CodeEditorShortcutsProps {
142 editorTheme: string
143 }
144
145 export const CodeEditorShortcuts: React.FC<CodeEditorShortcutsProps> = ({ editorTheme }) => {
146 const { codeEditorInstance } = useSnippetForm()
147
148 const shortcutKeys: Map<string, string[]> | undefined = useMemo(() => {
149 if (codeEditorInstance) {
150 const extraKeys = codeEditorInstance.codemirror.getOption('extraKeys')
151 const keyMapName = codeEditorInstance.codemirror.getOption('keyMap')
152
153 const combinedKeyMap: KeyMap = {
154 ...isMacOS() ? fallbackKeyMapMac : fallbackKeyMap,
155 ...keyMapName && getKeyMap(keyMapName),
156 ...'object' === typeof extraKeys ? extraKeys : undefined
157 }
158
159 return unpackKeyMap(combinedKeyMap)
160 }
161
162 return undefined
163 },
164 [codeEditorInstance]
165 )
166
167 return shortcutKeys
168 ? <div className="snippet-editor-help tooltip tooltip-inline tooltip-start">
169 <span className={`dashicons dashicons-editor-help cm-s-${editorTheme}`} aria-hidden="true"></span>
170
171 <div className="tooltip-content">
172 <table>
173 <tbody>
174 {Object.entries(keyMapLabels).map(([action, label]) => {
175 const keys = shortcutKeys.get(action)
176 return keys
177 ? <tr key={action}>
178 <td>{label}</td>
179 <td>
180 {isMacOS()
181 ? <KeyboardShortcutMac
182 keys={keys}
183 keyLabels={KEYBOARD_KEYS}
184 keySymbols={KEYBOARD_SYMBOLS}
185 />
186 : <KeyboardShortcutPC
187 keys={keys}
188 keyLabels={KEYBOARD_KEYS}
189 />}
190 </td>
191 </tr>
192 : null
193 })}
194 </tbody>
195 </table>
196 </div>
197 </div>
198 : null
199 }
200