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 } : {}) });
|
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;
|
if (isSpectator || !isMyTurn || isGameOver) return false;
|
||||||
const testGame = new Chess(localFenRef.current);
|
const testGame = new Chess(localFenRef.current);
|
||||||
const piece = testGame.get(sourceSquare as any);
|
const piece = testGame.get(sourceSquare as any);
|
||||||
@@ -347,15 +348,13 @@ export function ChessBoard({ state, myPlayerId, isSpectator, onAction, players }
|
|||||||
|
|
||||||
function handlePromotion(piece: string) {
|
function handlePromotion(piece: string) {
|
||||||
if (promotionFrom && promotionTo) {
|
if (promotionFrom && promotionTo) {
|
||||||
const promotionPiece = piece[1]?.toLowerCase() ?? "q";
|
dispatchMove(promotionFrom, promotionTo, piece);
|
||||||
dispatchMove(promotionFrom, promotionTo, promotionPiece);
|
|
||||||
}
|
}
|
||||||
setPromotionFrom(null);
|
setPromotionFrom(null);
|
||||||
setPromotionTo(null);
|
setPromotionTo(null);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function onSquareClick(square: string) {
|
function onSquareClick({ square }: { piece: any; square: string }) {
|
||||||
if (isSpectator || isGameOver || !isMyTurn) return;
|
if (isSpectator || isGameOver || !isMyTurn) return;
|
||||||
if (promotionFrom !== null) return;
|
if (promotionFrom !== null) return;
|
||||||
const testGame = new Chess(localFenRef.current);
|
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);
|
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;
|
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;
|
return isBothSides ? pieceColor === turn : pieceColor === myColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -472,26 +471,41 @@ export function ChessBoard({ state, myPlayerId, isSpectator, onAction, players }
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Board wrapper */}
|
{/* Board wrapper */}
|
||||||
<div ref={containerRef} className="relative" style={{ lineHeight: 0 }}>
|
<div ref={containerRef} className="relative" style={{ lineHeight: 0, width: boardWidth, maxWidth: "100%" }}>
|
||||||
<Chessboard
|
<Chessboard
|
||||||
position={localFen}
|
options={{
|
||||||
onPieceDrop={onDrop}
|
position: localFen,
|
||||||
onPromotionPieceSelect={handlePromotion}
|
onPieceDrop: onDrop,
|
||||||
onSquareClick={onSquareClick}
|
onSquareClick: onSquareClick,
|
||||||
boardOrientation={boardOrientation}
|
boardOrientation: boardOrientation,
|
||||||
isDraggablePiece={isDraggablePiece}
|
canDragPiece: canDragPiece,
|
||||||
boardWidth={boardWidth}
|
animationDurationInMs: 150,
|
||||||
showPromotionDialog={promotionFrom !== null}
|
squareStyles: customSquareStyles,
|
||||||
promotionToSquare={promotionTo as any}
|
darkSquareStyle: { backgroundColor: DARK_SQUARE },
|
||||||
animationDuration={150}
|
lightSquareStyle: { backgroundColor: LIGHT_SQUARE },
|
||||||
customSquareStyles={customSquareStyles}
|
boardStyle: { borderRadius: "0" },
|
||||||
customDarkSquareStyle={{ backgroundColor: DARK_SQUARE }}
|
dropSquareStyle: { boxShadow: "inset 0 0 1px 6px rgba(20,85,30,0.7)" },
|
||||||
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" }}
|
|
||||||
/>
|
/>
|
||||||
|
{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 && (
|
{isGameOver && (
|
||||||
<GameOverOverlay
|
<GameOverOverlay
|
||||||
status={chess.status}
|
status={chess.status}
|
||||||
|
|||||||
Reference in New Issue
Block a user