feat: Added "Keyboard shortcuts" help dialog. Can be opened by pressing Shift + ?
This commit is contained in:
@@ -1,7 +1,10 @@
|
||||
import { KeyboardCommand } from './KeyboardCommands'
|
||||
import { KeyboardShortcutCategory } from './KeyboardShortcut'
|
||||
|
||||
export type KeyboardCommandHandler = {
|
||||
command: KeyboardCommand
|
||||
category?: KeyboardShortcutCategory
|
||||
description?: string
|
||||
onKeyDown?: (event: KeyboardEvent, data?: unknown) => boolean | void
|
||||
onKeyUp?: (event: KeyboardEvent, data?: unknown) => boolean | void
|
||||
element?: HTMLElement
|
||||
|
||||
@@ -39,3 +39,5 @@ export const SUPER_EXPORT_MARKDOWN = createKeyboardCommand('SUPER_EXPORT_MARKDOW
|
||||
export const OPEN_PREFERENCES_COMMAND = createKeyboardCommand('OPEN_PREFERENCES_COMMAND')
|
||||
|
||||
export const CHANGE_EDITOR_WIDTH_COMMAND = createKeyboardCommand('CHANGE_EDITOR_WIDTH_COMMAND')
|
||||
|
||||
export const TOGGLE_KEYBOARD_SHORTCUTS_MODAL = createKeyboardCommand('TOGGLE_KEYBOARD_SHORTCUTS_MODAL')
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
import { Platform } from '@standardnotes/models'
|
||||
import { isMacPlatform } from './platformCheck'
|
||||
|
||||
export enum KeyboardModifier {
|
||||
Shift = 'Shift',
|
||||
Ctrl = 'Control',
|
||||
@@ -5,3 +8,7 @@ export enum KeyboardModifier {
|
||||
Meta = 'Meta',
|
||||
Alt = 'Alt',
|
||||
}
|
||||
|
||||
export function getPrimaryModifier(platform: Platform): KeyboardModifier {
|
||||
return isMacPlatform(platform) ? KeyboardModifier.Meta : KeyboardModifier.Ctrl
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import { KeyboardCommand } from './KeyboardCommands'
|
||||
import { KeyboardKeyEvent } from './KeyboardKeyEvent'
|
||||
import { KeyboardModifier } from './KeyboardModifier'
|
||||
import { KeyboardCommandHandler } from './KeyboardCommandHandler'
|
||||
import { KeyboardShortcut, PlatformedKeyboardShortcut } from './KeyboardShortcut'
|
||||
import { KeyboardShortcut, KeyboardShortcutHelpItem, PlatformedKeyboardShortcut } from './KeyboardShortcut'
|
||||
import { getKeyboardShortcuts } from './getKeyboardShortcuts'
|
||||
|
||||
export class KeyboardService {
|
||||
@@ -12,6 +12,8 @@ export class KeyboardService {
|
||||
private commandHandlers = new Set<KeyboardCommandHandler>()
|
||||
private commandMap = new Map<KeyboardCommand, KeyboardShortcut>()
|
||||
|
||||
private keyboardShortcutHelpItems = new Set<KeyboardShortcutHelpItem>()
|
||||
|
||||
constructor(
|
||||
private platform: Platform,
|
||||
environment: Environment,
|
||||
@@ -190,10 +192,18 @@ export class KeyboardService {
|
||||
addCommandHandler(observer: KeyboardCommandHandler): () => void {
|
||||
this.commandHandlers.add(observer)
|
||||
|
||||
const helpItem = this.getKeyboardShortcutHelpItemForHandler(observer)
|
||||
if (helpItem) {
|
||||
this.keyboardShortcutHelpItems.add(helpItem)
|
||||
}
|
||||
|
||||
return () => {
|
||||
observer.onKeyDown = undefined
|
||||
observer.onKeyDown = undefined
|
||||
this.commandHandlers.delete(observer)
|
||||
if (helpItem) {
|
||||
this.keyboardShortcutHelpItems.delete(helpItem)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -217,4 +227,48 @@ export class KeyboardService {
|
||||
...shortcut,
|
||||
}
|
||||
}
|
||||
|
||||
getKeyboardShortcutHelpItemForHandler(handler: KeyboardCommandHandler): KeyboardShortcutHelpItem | undefined {
|
||||
const shortcut = this.keyboardShortcutForCommand(handler.command)
|
||||
|
||||
if (!shortcut || !handler.category || !handler.description) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
return {
|
||||
...shortcut,
|
||||
category: handler.category,
|
||||
description: handler.description,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register help item for a keyboard shortcut that is handled outside of the KeyboardService,
|
||||
* for example by a library like Lexical.
|
||||
*/
|
||||
registerExternalKeyboardShortcutHelpItem(item: KeyboardShortcutHelpItem): () => void {
|
||||
this.keyboardShortcutHelpItems.add(item)
|
||||
|
||||
return () => {
|
||||
this.keyboardShortcutHelpItems.delete(item)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register help item for a keyboard shortcut that is handled outside of the KeyboardService,
|
||||
* for example by a library like Lexical.
|
||||
*/
|
||||
registerExternalKeyboardShortcutHelpItems(items: KeyboardShortcutHelpItem[]): () => void {
|
||||
const disposers = items.map((item) => this.registerExternalKeyboardShortcutHelpItem(item))
|
||||
|
||||
return () => {
|
||||
for (const disposer of disposers) {
|
||||
disposer()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getRegisteredKeyboardShorcutHelpItems(): KeyboardShortcutHelpItem[] {
|
||||
return Array.from(this.keyboardShortcutHelpItems)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,3 +18,10 @@ export type KeyboardShortcut = {
|
||||
export type PlatformedKeyboardShortcut = KeyboardShortcut & {
|
||||
platform: Platform
|
||||
}
|
||||
|
||||
export type KeyboardShortcutCategory = 'General' | 'Notes list' | 'Current note' | 'Super notes' | 'Formatting'
|
||||
|
||||
export type KeyboardShortcutHelpItem = Omit<PlatformedKeyboardShortcut, 'command'> & {
|
||||
category: KeyboardShortcutCategory
|
||||
description: string
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { Environment, Platform } from '@standardnotes/models'
|
||||
import { isMacPlatform } from './platformCheck'
|
||||
import {
|
||||
CREATE_NEW_NOTE_KEYBOARD_COMMAND,
|
||||
TOGGLE_LIST_PANE_KEYBOARD_COMMAND,
|
||||
@@ -31,15 +30,14 @@ import {
|
||||
SUPER_SEARCH_TOGGLE_REPLACE_MODE,
|
||||
CHANGE_EDITOR_WIDTH_COMMAND,
|
||||
SUPER_TOGGLE_TOOLBAR,
|
||||
TOGGLE_KEYBOARD_SHORTCUTS_MODAL,
|
||||
} from './KeyboardCommands'
|
||||
import { KeyboardKey } from './KeyboardKey'
|
||||
import { KeyboardModifier } from './KeyboardModifier'
|
||||
import { KeyboardModifier, getPrimaryModifier } from './KeyboardModifier'
|
||||
import { KeyboardShortcut } from './KeyboardShortcut'
|
||||
|
||||
export function getKeyboardShortcuts(platform: Platform, _environment: Environment): KeyboardShortcut[] {
|
||||
const isMac = isMacPlatform(platform)
|
||||
|
||||
const primaryModifier = isMac ? KeyboardModifier.Meta : KeyboardModifier.Ctrl
|
||||
const primaryModifier = getPrimaryModifier(platform)
|
||||
|
||||
return [
|
||||
{
|
||||
@@ -195,5 +193,11 @@ export function getKeyboardShortcuts(platform: Platform, _environment: Environme
|
||||
modifiers: [primaryModifier, KeyboardModifier.Shift],
|
||||
preventDefault: true,
|
||||
},
|
||||
{
|
||||
command: TOGGLE_KEYBOARD_SHORTCUTS_MODAL,
|
||||
key: '?',
|
||||
preventDefault: true,
|
||||
modifiers: [KeyboardModifier.Shift],
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
20
packages/ui-services/src/Keyboard/keyboardCharacterForKey.ts
Normal file
20
packages/ui-services/src/Keyboard/keyboardCharacterForKey.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
export function keyboardCharacterForKeyOrCode(keyOrCode: string) {
|
||||
if (keyOrCode.startsWith('Digit')) {
|
||||
return keyOrCode.replace('Digit', '')
|
||||
}
|
||||
if (keyOrCode.startsWith('Key')) {
|
||||
return keyOrCode.replace('Key', '')
|
||||
}
|
||||
switch (keyOrCode) {
|
||||
case 'ArrowDown':
|
||||
return '↓'
|
||||
case 'ArrowUp':
|
||||
return '↑'
|
||||
case 'ArrowLeft':
|
||||
return '←'
|
||||
case 'ArrowRight':
|
||||
return '→'
|
||||
default:
|
||||
return keyOrCode
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ export * from './Keyboard/KeyboardCommands'
|
||||
export * from './Keyboard/platformCheck'
|
||||
export * from './Keyboard/KeyboardKey'
|
||||
export * from './Keyboard/KeyboardModifier'
|
||||
export * from './Keyboard/keyboardCharacterForKey'
|
||||
export * from './Keyboard/keyboardCharacterForModifier'
|
||||
export * from './Keyboard/keyboardStringForShortcut'
|
||||
export * from './Route/Params/DemoParams'
|
||||
|
||||
Reference in New Issue
Block a user