fix(chess): migrate ChessBoard to react-chessboard v5 API
Some checks failed
Deploy to Production / test (push) Failing after 33s
Some checks failed
Deploy to Production / test (push) Failing after 33s
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 <noreply@anthropic.com>
This commit is contained in:
@@ -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 */}
|
||||
<div ref={containerRef} className="relative" style={{ lineHeight: 0 }}>
|
||||
<div ref={containerRef} className="relative" style={{ lineHeight: 0, width: boardWidth, maxWidth: "100%" }}>
|
||||
<Chessboard
|
||||
position={localFen}
|
||||
onPieceDrop={onDrop}
|
||||
onPromotionPieceSelect={handlePromotion}
|
||||
onSquareClick={onSquareClick}
|
||||
boardOrientation={boardOrientation}
|
||||
isDraggablePiece={isDraggablePiece}
|
||||
boardWidth={boardWidth}
|
||||
showPromotionDialog={promotionFrom !== null}
|
||||
promotionToSquare={promotionTo as any}
|
||||
animationDuration={150}
|
||||
customSquareStyles={customSquareStyles}
|
||||
customDarkSquareStyle={{ backgroundColor: DARK_SQUARE }}
|
||||
customLightSquareStyle={{ backgroundColor: LIGHT_SQUARE }}
|
||||
customBoardStyle={{ borderRadius: "0" }}
|
||||
customDropSquareStyle={{ boxShadow: "inset 0 0 1px 6px rgba(20,85,30,0.7)" }}
|
||||
customPremoveDarkSquareStyle={{ backgroundColor: "#a04a4a" }}
|
||||
customPremoveLightSquareStyle={{ backgroundColor: "#d08080" }}
|
||||
options={{
|
||||
position: localFen,
|
||||
onPieceDrop: onDrop,
|
||||
onSquareClick: onSquareClick,
|
||||
boardOrientation: boardOrientation,
|
||||
canDragPiece: canDragPiece,
|
||||
animationDurationInMs: 150,
|
||||
squareStyles: customSquareStyles,
|
||||
darkSquareStyle: { backgroundColor: DARK_SQUARE },
|
||||
lightSquareStyle: { backgroundColor: LIGHT_SQUARE },
|
||||
boardStyle: { borderRadius: "0" },
|
||||
dropSquareStyle: { boxShadow: "inset 0 0 1px 6px rgba(20,85,30,0.7)" },
|
||||
}}
|
||||
/>
|
||||
{promotionFrom !== null && (
|
||||
<div
|
||||
className="absolute inset-0 flex items-center justify-center z-20"
|
||||
style={{ backgroundColor: "rgba(20, 18, 15, 0.7)" }}
|
||||
>
|
||||
<div className="flex gap-1 p-2 rounded-lg" style={{ backgroundColor: "#1a1917", border: "1px solid #3a3733" }}>
|
||||
{["q", "r", "b", "n"].map((p) => (
|
||||
<button
|
||||
key={p}
|
||||
onClick={() => handlePromotion(p)}
|
||||
className="w-12 h-12 flex items-center justify-center text-2xl rounded hover:bg-white/10 transition-colors"
|
||||
style={{ color: "#f0d9b5" }}
|
||||
>
|
||||
{{ q: turn === "white" ? "♕" : "♛", r: turn === "white" ? "♖" : "♜", b: turn === "white" ? "♗" : "♝", n: turn === "white" ? "♘" : "♞" }[p]}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{isGameOver && (
|
||||
<GameOverOverlay
|
||||
status={chess.status}
|
||||
|
||||
Reference in New Issue
Block a user