You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

useKeyboardShortcuts.tsx 4.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. import * as React from 'react'
  2. import { inputs } from '@tldraw/core'
  3. import { useHotkeys } from 'react-hotkeys-hook'
  4. import { TLDrawShapeType } from '~types'
  5. import type { TLDrawState } from '~state'
  6. export function useKeyboardShortcuts(tlstate: TLDrawState) {
  7. React.useEffect(() => {
  8. const handleKeyDown = (e: KeyboardEvent) => {
  9. const info = inputs.keydown(e)
  10. tlstate.onKeyDown(e.key, info)
  11. }
  12. const handleKeyUp = (e: KeyboardEvent) => {
  13. const info = inputs.keyup(e)
  14. tlstate.onKeyUp(e.key, info)
  15. }
  16. window.addEventListener('keydown', handleKeyDown)
  17. window.addEventListener('keyup', handleKeyUp)
  18. return () => {
  19. window.removeEventListener('keydown', handleKeyDown)
  20. window.removeEventListener('keyup', handleKeyUp)
  21. }
  22. }, [tlstate])
  23. /* ---------------------- Tools --------------------- */
  24. useHotkeys('v,1', (e) => {
  25. tlstate.selectTool('select')
  26. e.preventDefault()
  27. })
  28. useHotkeys('d,2', (e) => {
  29. tlstate.selectTool(TLDrawShapeType.Draw)
  30. e.preventDefault()
  31. })
  32. useHotkeys('r,3', (e) => {
  33. tlstate.selectTool(TLDrawShapeType.Rectangle)
  34. e.preventDefault()
  35. })
  36. useHotkeys('e,4', (e) => {
  37. tlstate.selectTool(TLDrawShapeType.Ellipse)
  38. e.preventDefault()
  39. })
  40. useHotkeys('a,5', (e) => {
  41. tlstate.selectTool(TLDrawShapeType.Arrow)
  42. e.preventDefault()
  43. })
  44. useHotkeys('t,6', (e) => {
  45. tlstate.selectTool(TLDrawShapeType.Text)
  46. e.preventDefault()
  47. })
  48. /* ---------------------- Misc ---------------------- */
  49. // Save
  50. useHotkeys('ctrl+s,command+s', (e) => {
  51. tlstate.save()
  52. e.preventDefault()
  53. })
  54. // Undo Redo
  55. useHotkeys('command+z', (e) => {
  56. tlstate.undo()
  57. e.preventDefault()
  58. })
  59. useHotkeys('ctrl+shift-z,command+shift+z', (e) => {
  60. tlstate.redo()
  61. e.preventDefault()
  62. })
  63. /* -------------------- Commands -------------------- */
  64. // Camera
  65. useHotkeys('ctrl+=,command+=', (e) => {
  66. tlstate.zoomIn()
  67. e.preventDefault()
  68. })
  69. useHotkeys('ctrl+-,command+-', (e) => {
  70. tlstate.zoomOut()
  71. e.preventDefault()
  72. })
  73. useHotkeys('shift+1', (e) => {
  74. tlstate.zoomToFit()
  75. e.preventDefault()
  76. })
  77. useHotkeys('shift+2', (e) => {
  78. tlstate.zoomToSelection()
  79. e.preventDefault()
  80. })
  81. useHotkeys('shift+0', (e) => {
  82. tlstate.zoomToActual()
  83. e.preventDefault()
  84. })
  85. // Duplicate
  86. useHotkeys('ctrl+d,command+d', (e) => {
  87. tlstate.duplicate()
  88. e.preventDefault()
  89. })
  90. // Flip
  91. useHotkeys('shift+h', (e) => {
  92. tlstate.flipHorizontal()
  93. e.preventDefault()
  94. })
  95. useHotkeys('shift+v', (e) => {
  96. tlstate.flipVertical()
  97. e.preventDefault()
  98. })
  99. // Cancel
  100. useHotkeys('escape', (e) => {
  101. tlstate.cancel()
  102. e.preventDefault()
  103. })
  104. // Delete
  105. useHotkeys('backspace', (e) => {
  106. tlstate.delete()
  107. e.preventDefault()
  108. })
  109. // Select All
  110. useHotkeys('command+a,ctrl+a', (e) => {
  111. tlstate.selectAll()
  112. e.preventDefault()
  113. })
  114. // Nudge
  115. useHotkeys('up', (e) => {
  116. tlstate.nudge([0, -1], false)
  117. e.preventDefault()
  118. })
  119. useHotkeys('right', (e) => {
  120. tlstate.nudge([1, 0], false)
  121. e.preventDefault()
  122. })
  123. useHotkeys('down', (e) => {
  124. tlstate.nudge([0, 1], false)
  125. e.preventDefault()
  126. })
  127. useHotkeys('left', (e) => {
  128. tlstate.nudge([-1, 0], false)
  129. e.preventDefault()
  130. })
  131. useHotkeys('shift+up', (e) => {
  132. tlstate.nudge([0, -1], true)
  133. e.preventDefault()
  134. })
  135. useHotkeys('shift+right', (e) => {
  136. tlstate.nudge([1, 0], true)
  137. e.preventDefault()
  138. })
  139. useHotkeys('shift+down', (e) => {
  140. tlstate.nudge([0, 1], true)
  141. e.preventDefault()
  142. })
  143. useHotkeys('shift+left', (e) => {
  144. tlstate.nudge([-1, 0], true)
  145. e.preventDefault()
  146. })
  147. // Copy & Paste
  148. useHotkeys('command+c,ctrl+c', (e) => {
  149. tlstate.copy()
  150. e.preventDefault()
  151. })
  152. useHotkeys('command+v,ctrl+v', (e) => {
  153. tlstate.paste()
  154. e.preventDefault()
  155. })
  156. // Move
  157. useHotkeys('[', (e) => {
  158. tlstate.moveBackward()
  159. e.preventDefault()
  160. })
  161. useHotkeys(']', (e) => {
  162. tlstate.moveForward()
  163. e.preventDefault()
  164. })
  165. useHotkeys('shift+[', (e) => {
  166. tlstate.moveToBack()
  167. e.preventDefault()
  168. })
  169. useHotkeys('shift+]', (e) => {
  170. tlstate.moveToFront()
  171. e.preventDefault()
  172. })
  173. useHotkeys('command+shift+backspace', (e) => {
  174. tlstate.reset()
  175. e.preventDefault()
  176. })
  177. }