From a170eb00d972844be8d26ca5e92d7671d9b468d3 Mon Sep 17 00:00:00 2001 From: Ryan Gregory Date: Tue, 7 Oct 2025 23:53:25 +0100 Subject: [PATCH] fix: arrow bugs - fixed issue where onSquareRightClick would fire upon drawing an arrow - fixed issue where right clicking, dragging into a piece, and releasing, all within the same square, would cause an arrow to show when right clicking on another square - fixed analysis board logic that would still try to find the best move in a draw --- commitlint.config.mjs | 3 ++ .../AnalysisBoard.stories.tsx | 2 +- src/ChessboardProvider.tsx | 15 ++++++-- src/Square.tsx | 37 +++++++++++++++---- 4 files changed, 45 insertions(+), 12 deletions(-) diff --git a/commitlint.config.mjs b/commitlint.config.mjs index 0616fb9..d719088 100644 --- a/commitlint.config.mjs +++ b/commitlint.config.mjs @@ -1,3 +1,6 @@ export default { extends: ['@commitlint/config-conventional'], + rules: { + 'body-max-line-length': [0, 'always', 100], // [enabled, condition, value] + }, }; diff --git a/docs/stories/advanced-examples/AnalysisBoard.stories.tsx b/docs/stories/advanced-examples/AnalysisBoard.stories.tsx index 701bd02..1ee2af4 100644 --- a/docs/stories/advanced-examples/AnalysisBoard.stories.tsx +++ b/docs/stories/advanced-examples/AnalysisBoard.stories.tsx @@ -35,7 +35,7 @@ export const AnalysisBoard: Story = { // when the chess game position changes, find the best move useEffect(() => { - if (!chessGame.isGameOver() || chessGame.isDraw()) { + if (!(chessGame.isGameOver() || chessGame.isDraw())) { findBestMove(); } }, [chessGame.fen()]); diff --git a/src/ChessboardProvider.tsx b/src/ChessboardProvider.tsx index f257278..22ca8c7 100644 --- a/src/ChessboardProvider.tsx +++ b/src/ChessboardProvider.tsx @@ -114,9 +114,9 @@ type ContextType = { positionDifferences: ReturnType; newArrowStartSquare: string | null; newArrowOverSquare: { square: string; color: string } | null; - setNewArrowStartSquare: (square: string) => void; + setNewArrowStartSquare: (square: string | null) => void; setNewArrowOverSquare: ( - square: string, + square: string | null, modifiers?: { shiftKey: boolean; ctrlKey: boolean }, ) => void; internalArrows: Arrow[]; @@ -498,13 +498,20 @@ export function ChessboardProvider({ }, [clearArrowsOnClick]); const setNewArrowOverSquareWithModifiers = useCallback( - (square: string, modifiers?: { shiftKey: boolean; ctrlKey: boolean }) => { + ( + square: string | null, + modifiers?: { shiftKey: boolean; ctrlKey: boolean }, + ) => { const color = modifiers?.shiftKey ? arrowOptions.secondaryColor : modifiers?.ctrlKey ? arrowOptions.tertiaryColor : arrowOptions.color; - setNewArrowOverSquare({ square, color }); + if (square) { + setNewArrowOverSquare({ square, color }); + } else { + setNewArrowOverSquare(null); + } }, [arrowOptions], ); diff --git a/src/Square.tsx b/src/Square.tsx index 9667c3e..bc1f7da 100644 --- a/src/Square.tsx +++ b/src/Square.tsx @@ -1,4 +1,4 @@ -import { memo } from 'react'; +import { memo, useState } from 'react'; import { useChessboardContext } from './ChessboardProvider'; import { @@ -27,6 +27,8 @@ export const Square = memo(function Square({ isLightSquare, isOver, }: SquareProps) { + // track if we are drawing an arrow so that onSquareRightClick is not fired when we finish drawing an arrow + const [isDrawingArrow, setIsDrawingArrow] = useState(false); const { id, allowDrawingArrows, @@ -93,10 +95,14 @@ export const Square = memo(function Square({ }} onContextMenu={(e) => { e.preventDefault(); - onSquareRightClick?.({ - piece: currentPosition[squareId] ?? null, - square: squareId, - }); + + if (!isDrawingArrow) { + onSquareRightClick?.({ + piece: currentPosition[squareId] ?? null, + square: squareId, + }); + } + setIsDrawingArrow(false); }} onMouseDown={(e) => { if (e.button === 0) { @@ -115,11 +121,20 @@ export const Square = memo(function Square({ }} onMouseUp={(e) => { if (e.button === 2) { - if (newArrowStartSquare) { + if ( + allowDrawingArrows && + newArrowStartSquare && + newArrowStartSquare !== squareId + ) { + setIsDrawingArrow(true); drawArrow(squareId, { shiftKey: e.shiftKey, ctrlKey: e.ctrlKey, }); + } else if (newArrowStartSquare === squareId) { + // right clicked the same square - clear the arrow start square + setNewArrowStartSquare(null); + setNewArrowOverSquare(null); } } onSquareMouseUp?.( @@ -132,11 +147,19 @@ export const Square = memo(function Square({ }} onMouseOver={(e) => { // right mouse button is held down and we are drawing an arrow - if (e.buttons === 2 && newArrowStartSquare) { + if ( + e.buttons === 2 && + allowDrawingArrows && + newArrowStartSquare && + newArrowStartSquare !== squareId + ) { setNewArrowOverSquare(squareId, { shiftKey: e.shiftKey, ctrlKey: e.ctrlKey, }); + } else if (newArrowStartSquare === squareId) { + // hovering back over the starting square - clear the over square + setNewArrowOverSquare(null); } onMouseOverSquare?.({ piece: currentPosition[squareId] ?? null,