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

686 wiersze
11 KiB
TypeScript
Czysty Zwykły widok Historia

2021-08-10 16:12:55 +00:00
import * as React from 'react'
import { useHotkeys } from 'react-hotkeys-hook'
import { AlignStyle, TDShapeType } from '~types'
import { useFileSystemHandlers, useTldrawApp } from '~hooks'
export function useKeyboardShortcuts(ref: React.RefObject<HTMLDivElement>) {
const app = useTldrawApp()
2021-08-10 16:12:55 +00:00
const canHandleEvent = React.useCallback(
(ignoreMenus = false) => {
const elm = ref.current
if (ignoreMenus && (app.isMenuOpen || app.settings.keepStyleMenuOpen)) return true
return elm && (document.activeElement === elm || elm.contains(document.activeElement))
},
[ref]
)
React.useEffect(() => {
if (!app) return
const handleCut = (e: ClipboardEvent) => {
if (!canHandleEvent(true)) return
if (app.readOnly) {
app.copy(undefined, e)
return
}
app.cut(undefined, e)
}
const handleCopy = (e: ClipboardEvent) => {
if (!canHandleEvent(true)) return
app.copy(undefined, e)
}
const handlePaste = (e: ClipboardEvent) => {
if (!canHandleEvent(true)) return
if (app.readOnly) return
app.paste(undefined, e)
}
document.addEventListener('cut', handleCut)
document.addEventListener('copy', handleCopy)
document.addEventListener('paste', handlePaste)
return () => {
document.removeEventListener('cut', handleCut)
document.removeEventListener('copy', handleCopy)
document.removeEventListener('paste', handlePaste)
}
}, [app])
2021-08-10 16:12:55 +00:00
/* ---------------------- Tools --------------------- */
2021-09-08 10:16:10 +00:00
useHotkeys(
'v,1',
() => {
if (!canHandleEvent(true)) return
app.selectTool('select')
2021-09-08 10:16:10 +00:00
},
[app, ref.current]
2021-09-08 10:16:10 +00:00
)
useHotkeys(
2021-12-04 14:51:40 +00:00
'd,p,2',
2021-09-08 10:16:10 +00:00
() => {
if (!canHandleEvent(true)) return
app.selectTool(TDShapeType.Draw)
2021-09-08 10:16:10 +00:00
},
undefined,
[app]
2021-09-08 10:16:10 +00:00
)
useHotkeys(
'e,3',
2021-09-08 10:16:10 +00:00
() => {
if (!canHandleEvent(true)) return
app.selectTool('erase')
2021-09-08 10:16:10 +00:00
},
undefined,
[app]
2021-09-08 10:16:10 +00:00
)
useHotkeys(
'r,4',
2021-09-08 10:16:10 +00:00
() => {
if (!canHandleEvent(true)) return
app.selectTool(TDShapeType.Rectangle)
2021-09-08 10:16:10 +00:00
},
undefined,
[app]
2021-09-08 10:16:10 +00:00
)
useHotkeys(
'o,5',
2021-09-08 10:16:10 +00:00
() => {
if (!canHandleEvent(true)) return
app.selectTool(TDShapeType.Ellipse)
2021-09-08 10:16:10 +00:00
},
undefined,
[app]
2021-09-08 10:16:10 +00:00
)
useHotkeys(
'g,6',
() => {
if (!canHandleEvent()) return
app.selectTool(TDShapeType.Triangle)
},
undefined,
[app]
)
useHotkeys(
'l,7',
2021-09-08 10:16:10 +00:00
() => {
if (!canHandleEvent(true)) return
app.selectTool(TDShapeType.Line)
2021-09-08 10:16:10 +00:00
},
undefined,
[app]
2021-09-08 10:16:10 +00:00
)
2021-08-10 16:12:55 +00:00
useHotkeys(
'a,8',
() => {
if (!canHandleEvent(true)) return
app.selectTool(TDShapeType.Arrow)
},
undefined,
[app]
)
useHotkeys(
't,9',
() => {
if (!canHandleEvent(true)) return
app.selectTool(TDShapeType.Text)
},
undefined,
[app]
)
useHotkeys(
's,0',
() => {
if (!canHandleEvent(true)) return
app.selectTool(TDShapeType.Sticky)
},
undefined,
[app]
)
2021-08-10 16:12:55 +00:00
/* ---------------------- Misc ---------------------- */
// Dark Mode
useHotkeys(
'ctrl+shift+d,⌘+shift+d',
(e) => {
if (!canHandleEvent(true)) return
app.toggleDarkMode()
e.preventDefault()
},
undefined,
[app]
)
// Focus Mode
useHotkeys(
'ctrl+.,⌘+.',
() => {
if (!canHandleEvent(true)) return
app.toggleFocusMode()
},
undefined,
[app]
)
useHotkeys(
'ctrl+shift+g,⌘+shift+g',
() => {
if (!canHandleEvent(true)) return
app.toggleGrid()
},
undefined,
[app]
)
// File System
const { onNewProject, onOpenProject, onSaveProject, onSaveProjectAs, onOpenMedia } =
useFileSystemHandlers()
useHotkeys(
'ctrl+n,⌘+n',
(e) => {
if (!canHandleEvent()) return
onNewProject(e)
},
undefined,
[app]
)
useHotkeys(
'ctrl+s,⌘+s',
(e) => {
if (!canHandleEvent()) return
onSaveProject(e)
},
undefined,
[app]
)
2021-08-10 16:12:55 +00:00
2021-09-08 10:16:10 +00:00
useHotkeys(
'ctrl+shift+s,⌘+shift+s',
(e) => {
if (!canHandleEvent()) return
onSaveProjectAs(e)
},
undefined,
[app]
)
useHotkeys(
'ctrl+o,⌘+o',
(e) => {
if (!canHandleEvent()) return
onOpenProject(e)
2021-09-08 10:16:10 +00:00
},
undefined,
[app]
2021-09-08 10:16:10 +00:00
)
2021-12-25 17:06:33 +00:00
useHotkeys(
'ctrl+u,⌘+u',
(e) => {
2021-12-25 17:06:33 +00:00
if (!canHandleEvent()) return
onOpenMedia(e)
},
undefined,
[app]
)
2021-08-10 16:12:55 +00:00
// Undo Redo
2021-09-08 10:16:10 +00:00
useHotkeys(
'⌘+z,ctrl+z',
2021-09-08 10:16:10 +00:00
() => {
if (!canHandleEvent(true)) return
if (app.session) {
app.cancelSession()
} else {
app.undo()
}
2021-09-08 10:16:10 +00:00
},
undefined,
[app]
2021-09-08 10:16:10 +00:00
)
useHotkeys(
'ctrl+shift+z,⌘+shift+z',
2021-09-08 10:16:10 +00:00
() => {
if (!canHandleEvent(true)) return
if (app.session) {
app.cancelSession()
} else {
app.redo()
}
2021-09-08 10:16:10 +00:00
},
undefined,
[app]
2021-09-08 10:16:10 +00:00
)
2021-08-10 16:12:55 +00:00
2021-08-15 14:35:23 +00:00
// Undo Redo
2021-09-08 10:16:10 +00:00
useHotkeys(
'⌘+u,ctrl+u',
2021-09-08 10:16:10 +00:00
() => {
if (!canHandleEvent()) return
app.undoSelect()
2021-09-08 10:16:10 +00:00
},
undefined,
[app]
2021-09-08 10:16:10 +00:00
)
useHotkeys(
'ctrl+shift-u,⌘+shift+u',
2021-09-08 10:16:10 +00:00
() => {
if (!canHandleEvent()) return
app.redoSelect()
2021-09-08 10:16:10 +00:00
},
undefined,
[app]
2021-09-08 10:16:10 +00:00
)
2021-08-15 14:35:23 +00:00
2021-08-10 16:12:55 +00:00
/* -------------------- Commands -------------------- */
// Camera
2021-09-08 10:16:10 +00:00
useHotkeys(
'ctrl+=,⌘+=,ctrl+num_subtract,⌘+num_subtract',
(e) => {
if (!canHandleEvent(true)) return
app.zoomIn()
e.preventDefault()
2021-09-08 10:16:10 +00:00
},
undefined,
[app]
2021-09-08 10:16:10 +00:00
)
useHotkeys(
'ctrl+-,⌘+-,ctrl+num_add,⌘+num_add',
(e) => {
if (!canHandleEvent(true)) return
app.zoomOut()
e.preventDefault()
2021-09-08 10:16:10 +00:00
},
undefined,
[app]
2021-09-08 10:16:10 +00:00
)
useHotkeys(
'shift+0,ctrl+numpad_0,⌘+numpad_0',
2021-09-08 10:16:10 +00:00
() => {
if (!canHandleEvent(true)) return
app.resetZoom()
2021-09-08 10:16:10 +00:00
},
undefined,
[app]
2021-09-08 10:16:10 +00:00
)
useHotkeys(
'shift+1',
2021-09-08 10:16:10 +00:00
() => {
if (!canHandleEvent(true)) return
app.zoomToFit()
2021-09-08 10:16:10 +00:00
},
undefined,
[app]
2021-09-08 10:16:10 +00:00
)
useHotkeys(
'shift+2',
2021-09-08 10:16:10 +00:00
() => {
if (!canHandleEvent(true)) return
app.zoomToSelection()
2021-09-08 10:16:10 +00:00
},
undefined,
[app]
2021-09-08 10:16:10 +00:00
)
2021-08-10 16:12:55 +00:00
// Duplicate
2021-09-08 10:16:10 +00:00
useHotkeys(
'ctrl+d,⌘+d',
(e) => {
if (!canHandleEvent()) return
app.duplicate()
e.preventDefault()
2021-09-08 10:16:10 +00:00
},
undefined,
[app]
2021-09-08 10:16:10 +00:00
)
2021-08-10 16:12:55 +00:00
// Flip
2021-09-08 10:16:10 +00:00
useHotkeys(
'shift+h',
() => {
if (!canHandleEvent(true)) return
app.flipHorizontal()
2021-09-08 10:16:10 +00:00
},
undefined,
[app]
2021-09-08 10:16:10 +00:00
)
useHotkeys(
'shift+v',
() => {
if (!canHandleEvent(true)) return
app.flipVertical()
2021-09-08 10:16:10 +00:00
},
undefined,
[app]
2021-09-08 10:16:10 +00:00
)
2021-08-10 16:12:55 +00:00
// Cancel
2021-09-08 10:16:10 +00:00
useHotkeys(
'escape',
() => {
if (!canHandleEvent(true)) return
app.cancel()
2021-09-08 10:16:10 +00:00
},
undefined,
[app]
2021-09-08 10:16:10 +00:00
)
2021-08-10 16:12:55 +00:00
// Delete
2021-09-08 10:16:10 +00:00
useHotkeys(
2021-11-19 20:26:16 +00:00
'backspace,del',
2021-09-08 10:16:10 +00:00
() => {
if (!canHandleEvent()) return
app.delete()
2021-09-08 10:16:10 +00:00
},
undefined,
[app]
2021-09-08 10:16:10 +00:00
)
2021-08-10 16:12:55 +00:00
// Select All
2021-09-08 10:16:10 +00:00
useHotkeys(
'⌘+a,ctrl+a',
2021-09-08 10:16:10 +00:00
() => {
if (!canHandleEvent(true)) return
app.selectAll()
2021-09-08 10:16:10 +00:00
},
undefined,
[app]
2021-09-08 10:16:10 +00:00
)
2021-08-10 16:12:55 +00:00
// Nudge
2021-09-08 10:16:10 +00:00
useHotkeys(
'up',
() => {
if (!canHandleEvent()) return
app.nudge([0, -1], false)
2021-09-08 10:16:10 +00:00
},
undefined,
[app]
2021-09-08 10:16:10 +00:00
)
useHotkeys(
'right',
() => {
if (!canHandleEvent()) return
app.nudge([1, 0], false)
2021-09-08 10:16:10 +00:00
},
undefined,
[app]
2021-09-08 10:16:10 +00:00
)
useHotkeys(
'down',
() => {
if (!canHandleEvent()) return
app.nudge([0, 1], false)
2021-09-08 10:16:10 +00:00
},
undefined,
[app]
2021-09-08 10:16:10 +00:00
)
useHotkeys(
'left',
() => {
if (!canHandleEvent()) return
app.nudge([-1, 0], false)
2021-09-08 10:16:10 +00:00
},
undefined,
[app]
2021-09-08 10:16:10 +00:00
)
useHotkeys(
'shift+up',
() => {
if (!canHandleEvent()) return
app.nudge([0, -1], true)
2021-09-08 10:16:10 +00:00
},
undefined,
[app]
2021-09-08 10:16:10 +00:00
)
useHotkeys(
'shift+right',
() => {
if (!canHandleEvent()) return
app.nudge([1, 0], true)
2021-09-08 10:16:10 +00:00
},
undefined,
[app]
2021-09-08 10:16:10 +00:00
)
useHotkeys(
'shift+down',
() => {
if (!canHandleEvent()) return
app.nudge([0, 1], true)
2021-09-08 10:16:10 +00:00
},
undefined,
[app]
2021-09-08 10:16:10 +00:00
)
useHotkeys(
'shift+left',
() => {
if (!canHandleEvent()) return
app.nudge([-1, 0], true)
2021-09-08 10:16:10 +00:00
},
undefined,
[app]
)
useHotkeys(
'⌘+shift+l,ctrl+shift+l',
() => {
if (!canHandleEvent()) return
app.toggleLocked()
},
undefined,
[app]
2021-09-08 10:16:10 +00:00
)
2021-08-10 16:12:55 +00:00
// Copy, Cut & Paste
2021-08-10 16:12:55 +00:00
// useHotkeys(
// '⌘+c,ctrl+c',
// () => {
// if (!canHandleEvent()) return
// app.copy()
// },
// undefined,
// [app]
// )
2021-09-08 10:16:10 +00:00
2022-02-13 12:37:01 +00:00
useHotkeys(
'⌘+shift+c,ctrl+shift+c',
(e) => {
2022-02-13 12:37:01 +00:00
if (!canHandleEvent()) return
app.copySvg()
e.preventDefault()
},
undefined,
[app]
)
// useHotkeys(
// '⌘+x,ctrl+x',
// () => {
// if (!canHandleEvent()) return
// app.cut()
// },
// undefined,
// [app]
// )
// useHotkeys(
// '⌘+v,ctrl+v',
// () => {
// if (!canHandleEvent()) return
// app.paste()
// },
// undefined,
// [app]
// )
2021-08-10 16:12:55 +00:00
// Group & Ungroup
2021-09-08 10:16:10 +00:00
useHotkeys(
'⌘+g,ctrl+g',
(e) => {
if (!canHandleEvent()) return
app.group()
e.preventDefault()
2021-09-08 10:16:10 +00:00
},
undefined,
[app]
2021-09-08 10:16:10 +00:00
)
useHotkeys(
'⌘+shift+g,ctrl+shift+g',
(e) => {
if (!canHandleEvent()) return
app.ungroup()
e.preventDefault()
2021-09-08 10:16:10 +00:00
},
undefined,
[app]
2021-09-08 10:16:10 +00:00
)
2021-08-10 16:12:55 +00:00
// Move
2021-09-08 10:16:10 +00:00
useHotkeys(
'[',
() => {
if (!canHandleEvent(true)) return
app.moveBackward()
2021-09-08 10:16:10 +00:00
},
undefined,
[app]
2021-09-08 10:16:10 +00:00
)
useHotkeys(
']',
() => {
if (!canHandleEvent(true)) return
app.moveForward()
2021-09-08 10:16:10 +00:00
},
undefined,
[app]
2021-09-08 10:16:10 +00:00
)
useHotkeys(
'shift+[',
() => {
if (!canHandleEvent(true)) return
app.moveToBack()
2021-09-08 10:16:10 +00:00
},
undefined,
[app]
2021-09-08 10:16:10 +00:00
)
useHotkeys(
'shift+]',
() => {
if (!canHandleEvent(true)) return
app.moveToFront()
2021-09-08 10:16:10 +00:00
},
undefined,
[app]
2021-09-08 10:16:10 +00:00
)
useHotkeys(
'ctrl+shift+backspace,⌘+shift+backspace',
(e) => {
if (!canHandleEvent()) return
if (app.settings.isDebugMode) {
app.resetDocument()
}
e.preventDefault()
2021-09-08 10:16:10 +00:00
},
undefined,
[app]
2021-09-08 10:16:10 +00:00
)
// Text Align
useHotkeys(
'alt+command+l,alt+ctrl+l',
(e) => {
if (!canHandleEvent(true)) return
app.style({ textAlign: AlignStyle.Start })
e.preventDefault()
},
undefined,
[app]
)
useHotkeys(
'alt+command+t,alt+ctrl+t',
(e) => {
if (!canHandleEvent(true)) return
app.style({ textAlign: AlignStyle.Middle })
e.preventDefault()
},
undefined,
[app]
)
useHotkeys(
'alt+command+r,alt+ctrl+r',
(e) => {
if (!canHandleEvent(true)) return
app.style({ textAlign: AlignStyle.End })
e.preventDefault()
},
undefined,
[app]
)
2021-08-10 16:12:55 +00:00
}