All files / src/hooks useUndoRedoKeyboardShortcuts.ts

47.22% Statements 17/36
50% Branches 17/34
50% Functions 2/4
68.42% Lines 13/19

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48      4068x                     4068x   332x 25x 15x   10x                     5x 5x             5x 5x     4065x 3969x 24408x    
import { useEffect } from "react";
 
/** Bind platform-standard undo/redo shortcuts outside editable controls. */
export function useUndoRedoKeyboardShortcuts({
  canUndo,
  canRedo,
  onUndo,
  onRedo,
}: {
  canUndo: boolean;
  canRedo: boolean;
  onUndo: () => void;
  onRedo: () => void;
}) {
  useEffect(() => {
    const handleKeyDown = (event: KeyboardEvent) => {
      Iif (!(event.ctrlKey || event.metaKey) || event.altKey) return;
      const key = event.key.toLowerCase();
      Iif (key !== "z" && key !== "y") return;
 
      const target = event.target;
      if (
        target instanceof HTMLElement &&
        (target.isContentEditable ||
          target.matches("input, textarea, [role='textbox']"))
      ) {
        return;
      }
 
      if ((key === "z" && event.shiftKey) || (key === "y" && !event.shiftKey)) {
        Iif (!canRedo) return;
        event.preventDefault();
        onRedo();
        return;
      }
 
      Iif (key !== "z") return;
 
      Iif (!canUndo) return;
      event.preventDefault();
      onUndo();
    };
 
    window.addEventListener("keydown", handleKeyDown);
    return () => window.removeEventListener("keydown", handleKeyDown);
  }, [canRedo, canUndo, onRedo, onUndo]);
}