mirror of
https://github.com/ArthurDanjou/ui.git
synced 2026-01-29 11:20:36 +01:00
feat(defineShortcuts): chained shortcuts + docs update (#282)
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
This commit is contained in:
committed by
Benjamin Canac
parent
dfccbcf1a9
commit
a67f691a00
@@ -48,6 +48,21 @@ defineShortcuts({
|
|||||||
</script>
|
</script>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Shortcuts keys are written as the literal keyboard key value. Combinations are made with `_` separator. Chained shortcuts are made with `-` separator.
|
||||||
|
|
||||||
|
Modifiers are also available:
|
||||||
|
- `meta`: acts as `Command` for MacOS and `Control` for others
|
||||||
|
- `ctrl`: acts as `Control`
|
||||||
|
- `shift`: acts as `Shift` and is only necessary for alphabetic keys
|
||||||
|
|
||||||
|
Examples of keys:
|
||||||
|
- `escape`: will trigger by hitting `Esc`
|
||||||
|
- `meta_k`: will trigger by hitting `⌘` and `K` at the same time on MacOS, and `Ctrl` and `K` on Windows and Linux
|
||||||
|
- `ctrl_k`: will trigger by hitting `Ctrl` and `K` at the same time on MacOS, Windows and Linux
|
||||||
|
- `shift_e`: will trigger by hitting `Shift` and `E` at the same time on MacOS, Windows and Linux
|
||||||
|
- `?`: will trigger by hitting `?` on some keyboard layouts, or for example `Shift` and `/`, which results in `?` on US Mac keyboards
|
||||||
|
- `g-d`: will trigger by hitting `g` then `d` with a maximum delay of 800ms by default
|
||||||
|
|
||||||
### `usingInput`
|
### `usingInput`
|
||||||
|
|
||||||
Prop: `usingInput?: string | boolean`
|
Prop: `usingInput?: string | boolean`
|
||||||
|
|||||||
@@ -14,9 +14,14 @@ export interface ShortcutsConfig {
|
|||||||
[key: string]: ShortcutConfig | Function
|
[key: string]: ShortcutConfig | Function
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ShortcutsOptions {
|
||||||
|
chainDelay?: number
|
||||||
|
}
|
||||||
|
|
||||||
interface Shortcut {
|
interface Shortcut {
|
||||||
handler: Function
|
handler: Function
|
||||||
condition: ComputedRef<Boolean>
|
condition: ComputedRef<Boolean>
|
||||||
|
chained: boolean
|
||||||
// KeyboardEvent attributes
|
// KeyboardEvent attributes
|
||||||
key: string
|
key: string
|
||||||
ctrlKey: boolean
|
ctrlKey: boolean
|
||||||
@@ -27,18 +32,43 @@ interface Shortcut {
|
|||||||
// keyCode?: number
|
// keyCode?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export const defineShortcuts = (config: ShortcutsConfig) => {
|
export const defineShortcuts = (config: ShortcutsConfig, options: ShortcutsOptions = {}) => {
|
||||||
const { macOS, usingInput } = useShortcuts()
|
const { macOS, usingInput } = useShortcuts()
|
||||||
|
|
||||||
let shortcuts: Shortcut[] = []
|
let shortcuts: Shortcut[] = []
|
||||||
|
|
||||||
|
const chainedInputs = ref([])
|
||||||
|
const clearChainedInput = () => {
|
||||||
|
chainedInputs.value.splice(0, chainedInputs.value.length)
|
||||||
|
}
|
||||||
|
const debouncedClearChainedInput = useDebounceFn(clearChainedInput, options.chainDelay ?? 800)
|
||||||
|
|
||||||
const onKeyDown = (e: KeyboardEvent) => {
|
const onKeyDown = (e: KeyboardEvent) => {
|
||||||
// Input autocomplete triggers a keydown event
|
// Input autocomplete triggers a keydown event
|
||||||
if (!e.key) { return }
|
if (!e.key) { return }
|
||||||
|
|
||||||
const alphabeticalKey = /^[a-z]{1}$/i.test(e.key)
|
const alphabeticalKey = /^[a-z]{1}$/i.test(e.key)
|
||||||
|
|
||||||
for (const shortcut of shortcuts) {
|
let chainedKey
|
||||||
|
chainedInputs.value.push(e.key)
|
||||||
|
// try matching a chained shortcut
|
||||||
|
if (chainedInputs.value.length >= 2) {
|
||||||
|
chainedKey = chainedInputs.value.slice(-2).join('-')
|
||||||
|
|
||||||
|
for (const shortcut of shortcuts.filter(s => s.chained)) {
|
||||||
|
if (shortcut.key !== chainedKey) { continue }
|
||||||
|
|
||||||
|
if (shortcut.condition.value) {
|
||||||
|
e.preventDefault()
|
||||||
|
shortcut.handler()
|
||||||
|
}
|
||||||
|
clearChainedInput()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// try matching a standard shortcut
|
||||||
|
for (const shortcut of shortcuts.filter(s => !s.chained)) {
|
||||||
if (e.key.toLowerCase() !== shortcut.key) { continue }
|
if (e.key.toLowerCase() !== shortcut.key) { continue }
|
||||||
if (e.metaKey !== shortcut.metaKey) { continue }
|
if (e.metaKey !== shortcut.metaKey) { continue }
|
||||||
if (e.ctrlKey !== shortcut.ctrlKey) { continue }
|
if (e.ctrlKey !== shortcut.ctrlKey) { continue }
|
||||||
@@ -52,8 +82,11 @@ export const defineShortcuts = (config: ShortcutsConfig) => {
|
|||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
shortcut.handler()
|
shortcut.handler()
|
||||||
}
|
}
|
||||||
|
clearChainedInput()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
debouncedClearChainedInput()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Map config to full detailled shortcuts
|
// Map config to full detailled shortcuts
|
||||||
@@ -63,15 +96,34 @@ export const defineShortcuts = (config: ShortcutsConfig) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Parse key and modifiers
|
// Parse key and modifiers
|
||||||
const keySplit = key.toLowerCase().split('_').map(k => k)
|
let shortcut: Partial<Shortcut>
|
||||||
let shortcut: Partial<Shortcut> = {
|
|
||||||
key: keySplit.filter(k => !['meta', 'ctrl', 'shift', 'alt'].includes(k)).join('_'),
|
if (key.includes('-') && key.includes('_')) {
|
||||||
metaKey: keySplit.includes('meta'),
|
console.trace('[Shortcut] Invalid key')
|
||||||
ctrlKey: keySplit.includes('ctrl'),
|
return null
|
||||||
shiftKey: keySplit.includes('shift'),
|
|
||||||
altKey: keySplit.includes('alt')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const chained = key.includes('-')
|
||||||
|
if (chained) {
|
||||||
|
shortcut = {
|
||||||
|
key: key.toLowerCase(),
|
||||||
|
metaKey: false,
|
||||||
|
ctrlKey: false,
|
||||||
|
shiftKey: false,
|
||||||
|
altKey: false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const keySplit = key.toLowerCase().split('_').map(k => k)
|
||||||
|
shortcut = {
|
||||||
|
key: keySplit.filter(k => !['meta', 'ctrl', 'shift', 'alt'].includes(k)).join('_'),
|
||||||
|
metaKey: keySplit.includes('meta'),
|
||||||
|
ctrlKey: keySplit.includes('ctrl'),
|
||||||
|
shiftKey: keySplit.includes('shift'),
|
||||||
|
altKey: keySplit.includes('alt')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
shortcut.chained = chained
|
||||||
|
|
||||||
// Convert Meta to Ctrl for non-MacOS
|
// Convert Meta to Ctrl for non-MacOS
|
||||||
if (!macOS.value && shortcut.metaKey && !shortcut.ctrlKey) {
|
if (!macOS.value && shortcut.metaKey && !shortcut.ctrlKey) {
|
||||||
shortcut.metaKey = false
|
shortcut.metaKey = false
|
||||||
|
|||||||
Reference in New Issue
Block a user