-
Notifications
You must be signed in to change notification settings - Fork 36
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor(KeyboardShortcuts): move code into separate folder
- Loading branch information
1 parent
ad4c501
commit d854c51
Showing
7 changed files
with
149 additions
and
125 deletions.
There are no files selected for viewing
8 changes: 4 additions & 4 deletions
8
...erences/__tests__/UserDefinitions.test.ts → ...eyboard/__tests__/UserDefinitions.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
72 changes: 72 additions & 0 deletions
72
specifyweb/frontend/js_src/lib/components/Keyboard/config.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
import { preferencesText } from '../../localization/preferences'; | ||
import type { RA, RR } from '../../utils/types'; | ||
|
||
/** | ||
* Because operating systems, browsers and browser extensions define many | ||
* keyboard shortcuts, many of which differ between operating systems, the set | ||
* of free keyboard shortcuts is quite small so it's difficult to have one | ||
* shortcut that works on all 3 platforms. | ||
* | ||
* To provide flexibility, without complicating the UI for people who only use | ||
* Specify on a single platform, we do the following: | ||
* - UI allows you to set keyboard shortcuts for the current platform only | ||
* - If you set keyboard shortcut on any platform, that shortcut is used on all | ||
* platforms, unless you explicitly edited the shortcut on the other platform | ||
* - If keyboard shortcut was not explicitly set, the default shortcut, if any | ||
* will be used | ||
*/ | ||
export type KeyboardShortcuts = Partial< | ||
RR<KeyboardPlatform, RA<string> | undefined> | ||
>; | ||
|
||
type KeyboardPlatform = 'mac' | 'other' | 'windows'; | ||
export const keyboardPlatform: KeyboardPlatform = | ||
navigator.platform.toLowerCase().includes('mac') || | ||
// Check for iphone || ipad || ipod | ||
navigator.platform.toLowerCase().includes('ip') | ||
? 'mac' | ||
: navigator.platform.toLowerCase().includes('win') | ||
? 'windows' | ||
: 'other'; | ||
|
||
const modifierKeys = ['Alt', 'Ctrl', 'Meta', 'Shift'] as const; | ||
export type ModifierKey = typeof modifierKeys[number]; | ||
export const allModifierKeys = new Set([ | ||
...modifierKeys, | ||
'AltGraph', | ||
'CapsLock', | ||
]); | ||
|
||
export const keyboardModifierLocalization: RR<ModifierKey, string> = { | ||
Alt: | ||
keyboardPlatform === 'mac' | ||
? preferencesText.macOption() | ||
: preferencesText.alt(), | ||
Ctrl: | ||
keyboardPlatform === 'mac' | ||
? preferencesText.macControl() | ||
: preferencesText.ctrl(), | ||
// This key should never appear in non-mac platforms | ||
Meta: preferencesText.macMeta(), | ||
Shift: | ||
keyboardPlatform === 'mac' | ||
? preferencesText.macShift() | ||
: preferencesText.shift(), | ||
}; | ||
|
||
/** | ||
* Do not allow binding a keyboard shortcut that includes only one of these | ||
* keys, without any modifier. | ||
* | ||
* For example, do not allow binding keyboard shortcuts to Tab key. That key is | ||
* important for accessibility and for keyboard navigation. Without it | ||
* you won't be able to tab your way to the "Save" button to save the | ||
* keyboard shortcut) | ||
*/ | ||
export const specialKeyboardKeys = new Set([ | ||
'Enter', | ||
'Tab', | ||
' ', | ||
'Escape', | ||
'Backspace', | ||
]); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
51 changes: 51 additions & 0 deletions
51
specifyweb/frontend/js_src/lib/components/Keyboard/utils.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
import type { LocalizedString } from 'typesafe-i18n'; | ||
|
||
import type { RA } from '../../utils/types'; | ||
import { localized } from '../../utils/types'; | ||
import type { KeyboardShortcuts, ModifierKey } from './config'; | ||
import { keyboardModifierLocalization, keyboardPlatform } from './config'; | ||
import { keyJoinSymbol } from './context'; | ||
|
||
const localizedKeyJoinSymbol = ' + '; | ||
export const localizeKeyboardShortcut = (shortcut: string): LocalizedString => | ||
localized( | ||
shortcut | ||
.split(keyJoinSymbol) | ||
.map((key) => keyboardModifierLocalization[key as ModifierKey] ?? key) | ||
.join(localizedKeyJoinSymbol) | ||
); | ||
|
||
/** | ||
* If there is a keyboard shortcut defined for current system, use it | ||
* (also, if current system explicitly has empty array of shortcuts, use it). | ||
* | ||
* Otherwise, use the keyboard shortcut from one of the other platforms if set, | ||
* but change meta to ctrl and vice versa as necessary. | ||
*/ | ||
export function resolvePlatformShortcuts( | ||
shortcut: KeyboardShortcuts | ||
): RA<string> | undefined { | ||
if ('platform' in shortcut) return shortcut[keyboardPlatform]; | ||
else if ('other' in shortcut) | ||
return keyboardPlatform === 'windows' | ||
? shortcut.other | ||
: shortcut.other?.map(replaceCtrlWithMeta); | ||
else if ('windows' in shortcut) | ||
return keyboardPlatform === 'other' | ||
? shortcut.other | ||
: shortcut.other?.map(replaceCtrlWithMeta); | ||
else if ('mac' in shortcut) return shortcut.other?.map(replaceMetaWithCtrl); | ||
else return undefined; | ||
} | ||
|
||
const replaceCtrlWithMeta = (shortcut: string): string => | ||
shortcut | ||
.split(keyJoinSymbol) | ||
.map((key) => (key === 'ctrl' ? 'meta' : key)) | ||
.join(keyJoinSymbol); | ||
|
||
const replaceMetaWithCtrl = (shortcut: string): string => | ||
shortcut | ||
.split(keyJoinSymbol) | ||
.map((key) => (key === 'meta' ? 'ctrl' : key)) | ||
.join(keyJoinSymbol); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters