您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

use-shortcuts.ts 6.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. import { useReactFlow } from 'reactflow'
  2. import { useKeyPress } from 'ahooks'
  3. import { useCallback } from 'react'
  4. import {
  5. getKeyboardKeyCodeBySystem,
  6. isEventTargetInputArea,
  7. } from '../utils'
  8. import { useWorkflowHistoryStore } from '../workflow-history-store'
  9. import { useWorkflowStore } from '../store'
  10. import {
  11. useEdgesInteractions,
  12. useNodesInteractions,
  13. useNodesSyncDraft,
  14. useWorkflowCanvasMaximize,
  15. useWorkflowMoveMode,
  16. useWorkflowOrganize,
  17. useWorkflowStartRun,
  18. } from '.'
  19. export const useShortcuts = (): void => {
  20. const {
  21. handleNodesCopy,
  22. handleNodesPaste,
  23. handleNodesDuplicate,
  24. handleNodesDelete,
  25. handleHistoryBack,
  26. handleHistoryForward,
  27. dimOtherNodes,
  28. undimAllNodes,
  29. } = useNodesInteractions()
  30. const { handleStartWorkflowRun } = useWorkflowStartRun()
  31. const { shortcutsEnabled: workflowHistoryShortcutsEnabled } = useWorkflowHistoryStore()
  32. const { handleSyncWorkflowDraft } = useNodesSyncDraft()
  33. const { handleEdgeDelete } = useEdgesInteractions()
  34. const workflowStore = useWorkflowStore()
  35. const {
  36. handleModeHand,
  37. handleModePointer,
  38. } = useWorkflowMoveMode()
  39. const { handleLayout } = useWorkflowOrganize()
  40. const { handleToggleMaximizeCanvas } = useWorkflowCanvasMaximize()
  41. const {
  42. zoomTo,
  43. getZoom,
  44. fitView,
  45. } = useReactFlow()
  46. // Zoom out to a minimum of 0.5 for shortcut
  47. const constrainedZoomOut = () => {
  48. const currentZoom = getZoom()
  49. const newZoom = Math.max(currentZoom - 0.1, 0.5)
  50. zoomTo(newZoom)
  51. }
  52. // Zoom in to a maximum of 1 for shortcut
  53. const constrainedZoomIn = () => {
  54. const currentZoom = getZoom()
  55. const newZoom = Math.min(currentZoom + 0.1, 1)
  56. zoomTo(newZoom)
  57. }
  58. const shouldHandleShortcut = useCallback((e: KeyboardEvent) => {
  59. const { showFeaturesPanel } = workflowStore.getState()
  60. return !showFeaturesPanel && !isEventTargetInputArea(e.target as HTMLElement)
  61. }, [workflowStore])
  62. useKeyPress(['delete', 'backspace'], (e) => {
  63. if (shouldHandleShortcut(e)) {
  64. e.preventDefault()
  65. handleNodesDelete()
  66. handleEdgeDelete()
  67. }
  68. })
  69. useKeyPress(`${getKeyboardKeyCodeBySystem('ctrl')}.c`, (e) => {
  70. const { showDebugAndPreviewPanel } = workflowStore.getState()
  71. if (shouldHandleShortcut(e) && !showDebugAndPreviewPanel) {
  72. e.preventDefault()
  73. handleNodesCopy()
  74. }
  75. }, { exactMatch: true, useCapture: true })
  76. useKeyPress(`${getKeyboardKeyCodeBySystem('ctrl')}.v`, (e) => {
  77. const { showDebugAndPreviewPanel } = workflowStore.getState()
  78. if (shouldHandleShortcut(e) && !showDebugAndPreviewPanel) {
  79. e.preventDefault()
  80. handleNodesPaste()
  81. }
  82. }, { exactMatch: true, useCapture: true })
  83. useKeyPress(`${getKeyboardKeyCodeBySystem('ctrl')}.d`, (e) => {
  84. if (shouldHandleShortcut(e)) {
  85. e.preventDefault()
  86. handleNodesDuplicate()
  87. }
  88. }, { exactMatch: true, useCapture: true })
  89. useKeyPress(`${getKeyboardKeyCodeBySystem('alt')}.r`, (e) => {
  90. if (shouldHandleShortcut(e)) {
  91. e.preventDefault()
  92. handleStartWorkflowRun()
  93. }
  94. }, { exactMatch: true, useCapture: true })
  95. useKeyPress(`${getKeyboardKeyCodeBySystem('ctrl')}.z`, (e) => {
  96. const { showDebugAndPreviewPanel } = workflowStore.getState()
  97. if (shouldHandleShortcut(e) && !showDebugAndPreviewPanel) {
  98. e.preventDefault()
  99. workflowHistoryShortcutsEnabled && handleHistoryBack()
  100. }
  101. }, { exactMatch: true, useCapture: true })
  102. useKeyPress(
  103. [`${getKeyboardKeyCodeBySystem('ctrl')}.y`, `${getKeyboardKeyCodeBySystem('ctrl')}.shift.z`],
  104. (e) => {
  105. if (shouldHandleShortcut(e)) {
  106. e.preventDefault()
  107. workflowHistoryShortcutsEnabled && handleHistoryForward()
  108. }
  109. },
  110. { exactMatch: true, useCapture: true },
  111. )
  112. useKeyPress('h', (e) => {
  113. if (shouldHandleShortcut(e)) {
  114. e.preventDefault()
  115. handleModeHand()
  116. }
  117. }, {
  118. exactMatch: true,
  119. useCapture: true,
  120. })
  121. useKeyPress('v', (e) => {
  122. if (shouldHandleShortcut(e)) {
  123. e.preventDefault()
  124. handleModePointer()
  125. }
  126. }, {
  127. exactMatch: true,
  128. useCapture: true,
  129. })
  130. useKeyPress(`${getKeyboardKeyCodeBySystem('ctrl')}.o`, (e) => {
  131. if (shouldHandleShortcut(e)) {
  132. e.preventDefault()
  133. handleLayout()
  134. }
  135. }, { exactMatch: true, useCapture: true })
  136. useKeyPress('f', (e) => {
  137. if (shouldHandleShortcut(e)) {
  138. e.preventDefault()
  139. handleToggleMaximizeCanvas()
  140. }
  141. }, {
  142. exactMatch: true,
  143. useCapture: true,
  144. })
  145. useKeyPress(`${getKeyboardKeyCodeBySystem('ctrl')}.1`, (e) => {
  146. if (shouldHandleShortcut(e)) {
  147. e.preventDefault()
  148. fitView()
  149. handleSyncWorkflowDraft()
  150. }
  151. }, {
  152. exactMatch: true,
  153. useCapture: true,
  154. })
  155. useKeyPress('shift.1', (e) => {
  156. if (shouldHandleShortcut(e)) {
  157. e.preventDefault()
  158. zoomTo(1)
  159. handleSyncWorkflowDraft()
  160. }
  161. }, {
  162. exactMatch: true,
  163. useCapture: true,
  164. })
  165. useKeyPress('shift.5', (e) => {
  166. if (shouldHandleShortcut(e)) {
  167. e.preventDefault()
  168. zoomTo(0.5)
  169. handleSyncWorkflowDraft()
  170. }
  171. }, {
  172. exactMatch: true,
  173. useCapture: true,
  174. })
  175. useKeyPress(`${getKeyboardKeyCodeBySystem('ctrl')}.dash`, (e) => {
  176. if (shouldHandleShortcut(e)) {
  177. e.preventDefault()
  178. constrainedZoomOut()
  179. handleSyncWorkflowDraft()
  180. }
  181. }, {
  182. exactMatch: true,
  183. useCapture: true,
  184. })
  185. useKeyPress(`${getKeyboardKeyCodeBySystem('ctrl')}.equalsign`, (e) => {
  186. if (shouldHandleShortcut(e)) {
  187. e.preventDefault()
  188. constrainedZoomIn()
  189. handleSyncWorkflowDraft()
  190. }
  191. }, {
  192. exactMatch: true,
  193. useCapture: true,
  194. })
  195. // Shift ↓
  196. useKeyPress(
  197. 'shift',
  198. (e) => {
  199. if (shouldHandleShortcut(e))
  200. dimOtherNodes()
  201. },
  202. {
  203. exactMatch: true,
  204. useCapture: true,
  205. events: ['keydown'],
  206. },
  207. )
  208. // Shift ↑
  209. useKeyPress(
  210. (e) => {
  211. return e.key === 'Shift'
  212. },
  213. (e) => {
  214. if (shouldHandleShortcut(e))
  215. undimAllNodes()
  216. },
  217. {
  218. exactMatch: true,
  219. useCapture: true,
  220. events: ['keyup'],
  221. },
  222. )
  223. }