Tldraw/packages/tldraw/src/hooks/useKeyboardShortcuts.tsx

508 wiersze
7.7 KiB
TypeScript

import * as React from 'react'
import { useHotkeys } from 'react-hotkeys-hook'
import { TLDrawShapeType } from '~types'
import { useFileSystemHandlers, useTLDrawContext } from '~hooks'
export function useKeyboardShortcuts(ref: React.RefObject<HTMLDivElement>) {
const { state } = useTLDrawContext()
const canHandleEvent = React.useCallback(() => {
const elm = ref.current
return elm && (document.activeElement === elm || elm.contains(document.activeElement))
}, [ref])
/* ---------------------- Tools --------------------- */
useHotkeys(
'v,1',
() => {
if (canHandleEvent()) state.selectTool('select')
},
[state, ref.current]
)
useHotkeys(
'd,2',
() => {
if (canHandleEvent()) state.selectTool(TLDrawShapeType.Draw)
},
undefined,
[state]
)
useHotkeys(
'r,3',
() => {
if (canHandleEvent()) state.selectTool(TLDrawShapeType.Rectangle)
},
undefined,
[state]
)
useHotkeys(
'e,4',
() => {
if (canHandleEvent()) state.selectTool(TLDrawShapeType.Ellipse)
},
undefined,
[state]
)
useHotkeys(
'a,5',
() => {
if (canHandleEvent()) state.selectTool(TLDrawShapeType.Arrow)
},
undefined,
[state]
)
useHotkeys(
't,6',
() => {
if (canHandleEvent()) state.selectTool(TLDrawShapeType.Text)
},
undefined,
[state]
)
useHotkeys(
'n,7',
() => {
if (canHandleEvent()) state.selectTool(TLDrawShapeType.Sticky)
},
undefined,
[state]
)
/* ---------------------- Misc ---------------------- */
// Dark Mode
useHotkeys(
'ctrl+shift+d,command+shift+d',
(e) => {
if (canHandleEvent()) {
state.toggleDarkMode()
e.preventDefault()
}
},
undefined,
[state]
)
// Focus Mode
useHotkeys(
'ctrl+.,command+.',
() => {
if (canHandleEvent()) state.toggleFocusMode()
},
undefined,
[state]
)
// File System
const { onNewProject, onOpenProject, onSaveProject, onSaveProjectAs } = useFileSystemHandlers()
useHotkeys(
'ctrl+n,command+n',
(e) => {
if (canHandleEvent()) {
onNewProject(e)
}
},
undefined,
[state]
)
useHotkeys(
'ctrl+s,command+s',
(e) => {
if (canHandleEvent()) {
onSaveProject(e)
}
},
undefined,
[state]
)
useHotkeys(
'ctrl+shift+s,command+shift+s',
(e) => {
if (canHandleEvent()) {
onSaveProjectAs(e)
}
},
undefined,
[state]
)
useHotkeys(
'ctrl+o,command+o',
(e) => {
if (canHandleEvent()) {
onOpenProject(e)
}
},
undefined,
[state]
)
// Undo Redo
useHotkeys(
'command+z,ctrl+z',
() => {
if (canHandleEvent()) {
if (state.session) {
state.cancelSession()
} else {
state.undo()
}
}
},
undefined,
[state]
)
useHotkeys(
'ctrl+shift-z,command+shift+z',
() => {
if (canHandleEvent()) {
if (state.session) {
state.cancelSession()
} else {
state.redo()
}
}
},
undefined,
[state]
)
// Undo Redo
useHotkeys(
'command+u,ctrl+u',
() => {
if (canHandleEvent()) state.undoSelect()
},
undefined,
[state]
)
useHotkeys(
'ctrl+shift-u,command+shift+u',
() => {
if (canHandleEvent()) state.redoSelect()
},
undefined,
[state]
)
/* -------------------- Commands -------------------- */
// Camera
useHotkeys(
'ctrl+=,command+=',
(e) => {
if (canHandleEvent()) {
state.zoomIn()
e.preventDefault()
}
},
undefined,
[state]
)
useHotkeys(
'ctrl+-,command+-',
(e) => {
if (canHandleEvent()) {
state.zoomOut()
e.preventDefault()
}
},
undefined,
[state]
)
useHotkeys(
'shift+1',
() => {
if (canHandleEvent()) state.zoomToFit()
},
undefined,
[state]
)
useHotkeys(
'shift+2',
() => {
if (canHandleEvent()) state.zoomToSelection()
},
undefined,
[state]
)
useHotkeys(
'shift+0',
() => {
if (canHandleEvent()) state.resetZoom()
},
undefined,
[state]
)
// Duplicate
useHotkeys(
'ctrl+d,command+d',
(e) => {
if (canHandleEvent()) {
state.duplicate()
e.preventDefault()
}
},
undefined,
[state]
)
// Flip
useHotkeys(
'shift+h',
() => {
if (canHandleEvent()) state.flipHorizontal()
},
undefined,
[state]
)
useHotkeys(
'shift+v',
() => {
if (canHandleEvent()) state.flipVertical()
},
undefined,
[state]
)
// Cancel
useHotkeys(
'escape',
() => {
if (canHandleEvent()) {
state.cancel()
}
},
undefined,
[state]
)
// Delete
useHotkeys(
'backspace',
() => {
if (canHandleEvent()) state.delete()
},
undefined,
[state]
)
// Select All
useHotkeys(
'command+a,ctrl+a',
() => {
if (canHandleEvent()) state.selectAll()
},
undefined,
[state]
)
// Nudge
useHotkeys(
'up',
() => {
if (canHandleEvent()) state.nudge([0, -1], false)
},
undefined,
[state]
)
useHotkeys(
'right',
() => {
if (canHandleEvent()) state.nudge([1, 0], false)
},
undefined,
[state]
)
useHotkeys(
'down',
() => {
if (canHandleEvent()) state.nudge([0, 1], false)
},
undefined,
[state]
)
useHotkeys(
'left',
() => {
if (canHandleEvent()) state.nudge([-1, 0], false)
},
undefined,
[state]
)
useHotkeys(
'shift+up',
() => {
if (canHandleEvent()) state.nudge([0, -1], true)
},
undefined,
[state]
)
useHotkeys(
'shift+right',
() => {
if (canHandleEvent()) state.nudge([1, 0], true)
},
undefined,
[state]
)
useHotkeys(
'shift+down',
() => {
if (canHandleEvent()) state.nudge([0, 1], true)
},
undefined,
[state]
)
useHotkeys(
'shift+left',
() => {
if (canHandleEvent()) state.nudge([-1, 0], true)
},
undefined,
[state]
)
// Copy, Cut & Paste
useHotkeys(
'command+c,ctrl+c',
() => {
if (canHandleEvent()) state.copy()
},
undefined,
[state]
)
useHotkeys(
'command+x,ctrl+x',
() => {
if (canHandleEvent()) state.cut()
},
undefined,
[state]
)
useHotkeys(
'command+v,ctrl+v',
() => {
if (canHandleEvent()) state.paste()
},
undefined,
[state]
)
// Group & Ungroup
useHotkeys(
'command+g,ctrl+g',
(e) => {
if (canHandleEvent()) {
state.group()
e.preventDefault()
}
},
undefined,
[state]
)
useHotkeys(
'command+shift+g,ctrl+shift+g',
(e) => {
if (canHandleEvent()) {
state.ungroup()
e.preventDefault()
}
},
undefined,
[state]
)
// Move
useHotkeys(
'[',
() => {
if (canHandleEvent()) state.moveBackward()
},
undefined,
[state]
)
useHotkeys(
']',
() => {
if (canHandleEvent()) state.moveForward()
},
undefined,
[state]
)
useHotkeys(
'shift+[',
() => {
if (canHandleEvent()) state.moveToBack()
},
undefined,
[state]
)
useHotkeys(
'shift+]',
() => {
if (canHandleEvent()) state.moveToFront()
},
undefined,
[state]
)
useHotkeys(
'command+shift+backspace',
(e) => {
if (canHandleEvent()) {
if (process.env.NODE_ENV === 'development') {
state.resetDocument()
}
e.preventDefault()
}
},
undefined,
[state]
)
}