89 lines
2.7 KiB
TypeScript
89 lines
2.7 KiB
TypeScript
import type { DocsShortcutBinding } from "@/lib/drive/docs-keyboard-shortcuts-config"
|
|
|
|
export type { DocsShortcutBinding }
|
|
|
|
export function isMacPlatform(): boolean {
|
|
if (typeof navigator === "undefined") return false
|
|
return (
|
|
/Mac|iPhone|iPad|iPod/.test(navigator.platform) ||
|
|
(navigator.userAgent.includes("Mac") && "ontouchend" in document)
|
|
)
|
|
}
|
|
|
|
export function docsModKeyLabel(): string {
|
|
return isMacPlatform() ? "⌘" : "Ctrl"
|
|
}
|
|
|
|
export function normalizeDocsShortcutBinding(
|
|
binding: DocsShortcutBinding
|
|
): Required<Pick<DocsShortcutBinding, "key">> & {
|
|
mod: boolean
|
|
shift: boolean
|
|
alt: boolean
|
|
} {
|
|
return {
|
|
key: binding.key.length === 1 ? binding.key.toLowerCase() : binding.key,
|
|
mod: binding.mod ?? true,
|
|
shift: binding.shift ?? false,
|
|
alt: binding.alt ?? false,
|
|
}
|
|
}
|
|
|
|
/** Display label, e.g. ⌘Z or Ctrl+Shift+V */
|
|
export function formatDocsShortcutBinding(binding: DocsShortcutBinding): string {
|
|
const normalized = normalizeDocsShortcutBinding(binding)
|
|
const mod = docsModKeyLabel()
|
|
const isMac = isMacPlatform()
|
|
const keyLabel =
|
|
normalized.key.length === 1 ? normalized.key.toUpperCase() : normalized.key
|
|
|
|
if (isMac) {
|
|
const parts: string[] = []
|
|
if (normalized.shift) parts.push("Maj")
|
|
if (normalized.alt) parts.push("⌥")
|
|
if (parts.length > 0) {
|
|
return `${mod}+${parts.join("+")}+${keyLabel}`
|
|
}
|
|
return normalized.mod ? `${mod}${keyLabel}` : keyLabel
|
|
}
|
|
|
|
const parts: string[] = []
|
|
if (normalized.shift) parts.push("Shift")
|
|
if (normalized.alt) parts.push("Alt")
|
|
if (normalized.mod) parts.push(mod)
|
|
parts.push(keyLabel)
|
|
return parts.join("+")
|
|
}
|
|
|
|
export function matchesDocsShortcutBinding(
|
|
event: KeyboardEvent,
|
|
binding: DocsShortcutBinding
|
|
): boolean {
|
|
const normalized = normalizeDocsShortcutBinding(binding)
|
|
const modPressed = isMacPlatform() ? event.metaKey : event.ctrlKey
|
|
|
|
if (normalized.mod && !modPressed) return false
|
|
if (!normalized.mod && modPressed) return false
|
|
|
|
const eventKey =
|
|
event.key.length === 1 ? event.key.toLowerCase() : event.key
|
|
|
|
if (eventKey !== normalized.key) return false
|
|
if (normalized.shift !== event.shiftKey) return false
|
|
if (normalized.alt !== event.altKey) return false
|
|
return true
|
|
}
|
|
|
|
/** TipTap key string, e.g. Mod-Shift-h */
|
|
export function docsShortcutBindingToTipTapKey(binding: DocsShortcutBinding): string {
|
|
const normalized = normalizeDocsShortcutBinding(binding)
|
|
const parts: string[] = []
|
|
if (normalized.mod) parts.push("Mod")
|
|
if (normalized.shift) parts.push("Shift")
|
|
if (normalized.alt) parts.push("Alt")
|
|
parts.push(
|
|
normalized.key.length === 1 ? normalized.key.toLowerCase() : normalized.key
|
|
)
|
|
return parts.join("-")
|
|
}
|