vim.ts 1.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. import { useThrottleCallback } from '@react-hook/throttle';
  2. import { Dispatch, useCallback, useEffect } from 'react';
  3. import { noop } from '../utils/noop';
  4. export const Keys = {
  5. tab: 'Tab',
  6. enter: 'Enter',
  7. esc: 'Escape',
  8. space: ' ',
  9. colon: ':',
  10. question: '?',
  11. pageDown: 'PageDown',
  12. pageUp: 'PageUp',
  13. slash: '/',
  14. '1': '1',
  15. '2': '2',
  16. '3': '3',
  17. B: 'b',
  18. C: 'c',
  19. D: 'd',
  20. E: 'e',
  21. J: 'j',
  22. K: 'k',
  23. P: 'P',
  24. p: 'p',
  25. S: 's',
  26. Z: 'z',
  27. };
  28. const availableKeys = Object.values(Keys);
  29. export const ActionTypeKeyPressed = '@@vim/KEY_PRESSED';
  30. export type ActionKeyPressed = {
  31. type: typeof ActionTypeKeyPressed;
  32. key: string;
  33. };
  34. export function useVimBindings(dispatch: Dispatch<ActionKeyPressed>, skip = false): void {
  35. const listener = useCallback(
  36. (event: KeyboardEvent): void => {
  37. if (!availableKeys.includes(event.key)) {
  38. return;
  39. }
  40. event.preventDefault();
  41. const action: ActionKeyPressed = { type: ActionTypeKeyPressed, key: event.key };
  42. dispatch(action);
  43. },
  44. [dispatch],
  45. );
  46. const listenerThrottled = useThrottleCallback(
  47. listener,
  48. process.env.NODE_ENV === 'development' ? 15 : 60,
  49. true,
  50. );
  51. useEffect(() => {
  52. if (skip) {
  53. return noop;
  54. }
  55. window.addEventListener('keydown', listenerThrottled);
  56. return (): void => {
  57. window.removeEventListener('keydown', listenerThrottled);
  58. };
  59. }, [skip, listenerThrottled]);
  60. }