From ebac1ad6cc7dc723c472c64a0dc996ddb00b83c5 Mon Sep 17 00:00:00 2001 From: syntaxbullet Date: Thu, 2 Apr 2026 19:26:24 +0200 Subject: [PATCH] fix(chess): migrate ChessBoard to react-chessboard v5 API react-chessboard v5 moved all props into an `options` object and renamed several callbacks/style props. The v4-style props were silently ignored, causing pieces to snap back, no legal-move highlights, and no WS events on drop. Also adds a custom promotion dialog since v5 removed the built-in one. Co-Authored-By: Claude Sonnet 4.6 --- panel/src/games/chess/ChessBoard.tsx | 64 +++++++++++++++++----------- 1 file changed, 39 insertions(+), 25 deletions(-) diff --git a/panel/src/games/chess/ChessBoard.tsx b/panel/src/games/chess/ChessBoard.tsx index 533a558..2ab8c00 100644 --- a/panel/src/games/chess/ChessBoard.tsx +++ b/panel/src/games/chess/ChessBoard.tsx @@ -325,7 +325,8 @@ export function ChessBoard({ state, myPlayerId, isSpectator, onAction, players } onAction({ type: "move", from, to, ...(promotion ? { promotion } : {}) }); } - function onDrop(sourceSquare: string, targetSquare: string): boolean { + function onDrop({ sourceSquare, targetSquare }: { piece: any; sourceSquare: string; targetSquare: string | null }): boolean { + if (!targetSquare) return false; if (isSpectator || !isMyTurn || isGameOver) return false; const testGame = new Chess(localFenRef.current); const piece = testGame.get(sourceSquare as any); @@ -347,15 +348,13 @@ export function ChessBoard({ state, myPlayerId, isSpectator, onAction, players } function handlePromotion(piece: string) { if (promotionFrom && promotionTo) { - const promotionPiece = piece[1]?.toLowerCase() ?? "q"; - dispatchMove(promotionFrom, promotionTo, promotionPiece); + dispatchMove(promotionFrom, promotionTo, piece); } setPromotionFrom(null); setPromotionTo(null); - return true; } - function onSquareClick(square: string) { + function onSquareClick({ square }: { piece: any; square: string }) { if (isSpectator || isGameOver || !isMyTurn) return; if (promotionFrom !== null) return; const testGame = new Chess(localFenRef.current); @@ -397,9 +396,9 @@ export function ChessBoard({ state, myPlayerId, isSpectator, onAction, players } if (isBothSides ? color === turn : color === myColor) setSelectedSquare(square); } - function isDraggablePiece({ piece }: { piece: string }): boolean { + function canDragPiece({ piece }: { isSparePiece: boolean; piece: { pieceType: string }; square: string | null }): boolean { if (isSpectator || !isMyTurn || isGameOver) return false; - const pieceColor = piece[0] === "w" ? "white" : "black"; + const pieceColor = piece.pieceType === piece.pieceType.toUpperCase() ? "white" : "black"; return isBothSides ? pieceColor === turn : pieceColor === myColor; } @@ -472,26 +471,41 @@ export function ChessBoard({ state, myPlayerId, isSpectator, onAction, players } /> {/* Board wrapper */} -
+
+ {promotionFrom !== null && ( +
+
+ {["q", "r", "b", "n"].map((p) => ( + + ))} +
+
+ )} {isGameOver && (