@react-chess-tools/react-chess-game 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/README.md +399 -0
- package/dist/index.cjs +180 -170
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +17 -3
- package/dist/index.d.ts +17 -3
- package/dist/index.js +180 -170
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
- package/src/components/ChessGame/Theme.stories.tsx +2 -2
- package/src/components/ChessGame/parts/Board.tsx +214 -205
- package/src/components/ChessGame/parts/KeyboardControls.tsx +9 -0
- package/src/components/ChessGame/parts/Root.tsx +2 -0
- package/src/components/ChessGame/parts/Sounds.tsx +9 -0
- package/src/components/ChessGame/parts/__tests__/Board.test.tsx +122 -0
- package/src/components/ChessGame/parts/__tests__/KeyboardControls.test.tsx +34 -0
- package/src/components/ChessGame/parts/__tests__/Root.test.tsx +50 -0
- package/src/components/ChessGame/parts/__tests__/Sounds.test.tsx +22 -0
- package/src/theme/__tests__/context.test.tsx +0 -15
- package/README.MD +0 -190
package/dist/index.js
CHANGED
|
@@ -306,6 +306,7 @@ var Root = ({
|
|
|
306
306
|
const mergedTheme = React4.useMemo(() => mergeTheme(theme), [theme]);
|
|
307
307
|
return /* @__PURE__ */ React4.createElement(ChessGameContext.Provider, { value: context }, /* @__PURE__ */ React4.createElement(ThemeProvider, { theme: mergedTheme }, children));
|
|
308
308
|
};
|
|
309
|
+
Root.displayName = "ChessGame.Root";
|
|
309
310
|
|
|
310
311
|
// src/components/ChessGame/parts/Board.tsx
|
|
311
312
|
import React5 from "react";
|
|
@@ -375,192 +376,199 @@ var deepMergeChessboardOptions = (baseOptions, customOptions) => {
|
|
|
375
376
|
};
|
|
376
377
|
|
|
377
378
|
// src/components/ChessGame/parts/Board.tsx
|
|
378
|
-
var Board = (
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
const {
|
|
386
|
-
game,
|
|
387
|
-
currentFen,
|
|
388
|
-
orientation,
|
|
389
|
-
info,
|
|
390
|
-
isLatestMove,
|
|
391
|
-
methods: { makeMove }
|
|
392
|
-
} = gameContext;
|
|
393
|
-
const { turn, isGameOver } = info;
|
|
394
|
-
const [activeSquare, setActiveSquare] = React5.useState(null);
|
|
395
|
-
const [promotionMove, setPromotionMove] = React5.useState(null);
|
|
396
|
-
const onSquareClick = (square) => {
|
|
397
|
-
if (isGameOver) {
|
|
398
|
-
return;
|
|
379
|
+
var Board = React5.forwardRef(
|
|
380
|
+
({ options = {}, className, style: userStyle, ...rest }, ref) => {
|
|
381
|
+
var _a, _b, _c;
|
|
382
|
+
const gameContext = useChessGameContext();
|
|
383
|
+
const theme = useChessGameTheme();
|
|
384
|
+
if (!gameContext) {
|
|
385
|
+
throw new Error("ChessGameContext not found");
|
|
399
386
|
}
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
387
|
+
const {
|
|
388
|
+
game,
|
|
389
|
+
currentFen,
|
|
390
|
+
orientation,
|
|
391
|
+
info,
|
|
392
|
+
isLatestMove,
|
|
393
|
+
methods: { makeMove }
|
|
394
|
+
} = gameContext;
|
|
395
|
+
const { turn, isGameOver } = info;
|
|
396
|
+
const [activeSquare, setActiveSquare] = React5.useState(null);
|
|
397
|
+
const [promotionMove, setPromotionMove] = React5.useState(null);
|
|
398
|
+
const onSquareClick = (square) => {
|
|
399
|
+
if (isGameOver) {
|
|
400
|
+
return;
|
|
404
401
|
}
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
}
|
|
414
|
-
if (requiresPromotion(game, {
|
|
415
|
-
from: activeSquare,
|
|
416
|
-
to: square,
|
|
417
|
-
promotion: "q"
|
|
418
|
-
})) {
|
|
419
|
-
return setPromotionMove({
|
|
402
|
+
if (activeSquare === null) {
|
|
403
|
+
const squadreInfo = game.get(square);
|
|
404
|
+
if (squadreInfo && squadreInfo.color === turn) {
|
|
405
|
+
return setActiveSquare(square);
|
|
406
|
+
}
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
409
|
+
if (!isLegalMove(game, {
|
|
420
410
|
from: activeSquare,
|
|
421
|
-
to: square
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
411
|
+
to: square,
|
|
412
|
+
promotion: "q"
|
|
413
|
+
})) {
|
|
414
|
+
return setActiveSquare(null);
|
|
415
|
+
}
|
|
416
|
+
if (requiresPromotion(game, {
|
|
417
|
+
from: activeSquare,
|
|
418
|
+
to: square,
|
|
419
|
+
promotion: "q"
|
|
420
|
+
})) {
|
|
421
|
+
return setPromotionMove({
|
|
422
|
+
from: activeSquare,
|
|
423
|
+
to: square
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
setActiveSquare(null);
|
|
432
427
|
makeMove({
|
|
433
|
-
from:
|
|
434
|
-
to:
|
|
435
|
-
promotion: piece.toLowerCase()
|
|
428
|
+
from: activeSquare,
|
|
429
|
+
to: square
|
|
436
430
|
});
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
if (typeof document === "undefined") return 80;
|
|
447
|
-
const squareElement = document.querySelector(`[data-square]`);
|
|
448
|
-
return ((_a2 = squareElement == null ? void 0 : squareElement.getBoundingClientRect()) == null ? void 0 : _a2.width) ?? 80;
|
|
449
|
-
}, [promotionMove]);
|
|
450
|
-
const promotionSquareLeft = React5.useMemo(() => {
|
|
451
|
-
var _a2;
|
|
452
|
-
if (!(promotionMove == null ? void 0 : promotionMove.to)) return 0;
|
|
453
|
-
const column = ((_a2 = promotionMove.to.match(/^[a-h]/)) == null ? void 0 : _a2[0]) ?? "a";
|
|
454
|
-
return squareWidth * chessColumnToColumnIndex(
|
|
455
|
-
column,
|
|
456
|
-
8,
|
|
457
|
-
orientation === "b" ? "black" : "white"
|
|
458
|
-
);
|
|
459
|
-
}, [promotionMove, squareWidth, orientation]);
|
|
460
|
-
const baseOptions = {
|
|
461
|
-
squareStyles: getCustomSquareStyles(game, info, activeSquare, theme),
|
|
462
|
-
boardOrientation: orientation === "b" ? "black" : "white",
|
|
463
|
-
position: currentFen,
|
|
464
|
-
showNotation: true,
|
|
465
|
-
showAnimations: isLatestMove,
|
|
466
|
-
lightSquareStyle: theme.board.lightSquare,
|
|
467
|
-
darkSquareStyle: theme.board.darkSquare,
|
|
468
|
-
canDragPiece: ({ piece }) => {
|
|
469
|
-
if (isGameOver) return false;
|
|
470
|
-
return piece.pieceType[0] === turn;
|
|
471
|
-
},
|
|
472
|
-
dropSquareStyle: theme.state.dropSquare,
|
|
473
|
-
onPieceDrag: ({ piece, square }) => {
|
|
474
|
-
if (piece.pieceType[0] === turn) {
|
|
475
|
-
setActiveSquare(square);
|
|
431
|
+
};
|
|
432
|
+
const onPromotionPieceSelect = (piece) => {
|
|
433
|
+
if ((promotionMove == null ? void 0 : promotionMove.from) && (promotionMove == null ? void 0 : promotionMove.to)) {
|
|
434
|
+
makeMove({
|
|
435
|
+
from: promotionMove.from,
|
|
436
|
+
to: promotionMove.to,
|
|
437
|
+
promotion: piece.toLowerCase()
|
|
438
|
+
});
|
|
439
|
+
setPromotionMove(null);
|
|
476
440
|
}
|
|
477
|
-
}
|
|
478
|
-
|
|
441
|
+
};
|
|
442
|
+
const onSquareRightClick = () => {
|
|
479
443
|
setActiveSquare(null);
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
if (
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
444
|
+
setPromotionMove(null);
|
|
445
|
+
};
|
|
446
|
+
const squareWidth = React5.useMemo(() => {
|
|
447
|
+
var _a2;
|
|
448
|
+
if (typeof document === "undefined") return 80;
|
|
449
|
+
const squareElement = document.querySelector(`[data-square]`);
|
|
450
|
+
return ((_a2 = squareElement == null ? void 0 : squareElement.getBoundingClientRect()) == null ? void 0 : _a2.width) ?? 80;
|
|
451
|
+
}, [promotionMove]);
|
|
452
|
+
const promotionSquareLeft = React5.useMemo(() => {
|
|
453
|
+
var _a2;
|
|
454
|
+
if (!(promotionMove == null ? void 0 : promotionMove.to)) return 0;
|
|
455
|
+
const column = ((_a2 = promotionMove.to.match(/^[a-h]/)) == null ? void 0 : _a2[0]) ?? "a";
|
|
456
|
+
return squareWidth * chessColumnToColumnIndex(
|
|
457
|
+
column,
|
|
458
|
+
8,
|
|
459
|
+
orientation === "b" ? "black" : "white"
|
|
460
|
+
);
|
|
461
|
+
}, [promotionMove, squareWidth, orientation]);
|
|
462
|
+
const baseOptions = {
|
|
463
|
+
squareStyles: getCustomSquareStyles(game, info, activeSquare, theme),
|
|
464
|
+
boardOrientation: orientation === "b" ? "black" : "white",
|
|
465
|
+
position: currentFen,
|
|
466
|
+
showNotation: true,
|
|
467
|
+
showAnimations: isLatestMove,
|
|
468
|
+
lightSquareStyle: theme.board.lightSquare,
|
|
469
|
+
darkSquareStyle: theme.board.darkSquare,
|
|
470
|
+
canDragPiece: ({ piece }) => {
|
|
471
|
+
if (isGameOver) return false;
|
|
472
|
+
return piece.pieceType[0] === turn;
|
|
507
473
|
},
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
474
|
+
dropSquareStyle: theme.state.dropSquare,
|
|
475
|
+
onPieceDrag: ({ piece, square }) => {
|
|
476
|
+
if (piece.pieceType[0] === turn) {
|
|
477
|
+
setActiveSquare(square);
|
|
478
|
+
}
|
|
479
|
+
},
|
|
480
|
+
onPieceDrop: ({ sourceSquare, targetSquare }) => {
|
|
481
|
+
setActiveSquare(null);
|
|
482
|
+
const moveData = {
|
|
483
|
+
from: sourceSquare,
|
|
484
|
+
to: targetSquare
|
|
485
|
+
};
|
|
486
|
+
if (requiresPromotion(game, { ...moveData, promotion: "q" })) {
|
|
487
|
+
setPromotionMove(moveData);
|
|
488
|
+
return false;
|
|
489
|
+
}
|
|
490
|
+
return makeMove(moveData);
|
|
491
|
+
},
|
|
492
|
+
onSquareClick: ({ square }) => {
|
|
493
|
+
if (square.match(/^[a-h][1-8]$/)) {
|
|
494
|
+
onSquareClick(square);
|
|
495
|
+
}
|
|
496
|
+
},
|
|
497
|
+
onSquareRightClick,
|
|
498
|
+
allowDrawingArrows: true,
|
|
499
|
+
animationDurationInMs: game.history().length === 0 ? 0 : 300
|
|
500
|
+
};
|
|
501
|
+
const mergedOptions = deepMergeChessboardOptions(baseOptions, options);
|
|
502
|
+
const mergedStyle = {
|
|
503
|
+
...userStyle,
|
|
504
|
+
position: "relative"
|
|
505
|
+
};
|
|
506
|
+
return /* @__PURE__ */ React5.createElement("div", { ref, className, style: mergedStyle, ...rest }, /* @__PURE__ */ React5.createElement(Chessboard, { options: mergedOptions }), promotionMove && /* @__PURE__ */ React5.createElement(React5.Fragment, null, /* @__PURE__ */ React5.createElement(
|
|
507
|
+
"div",
|
|
536
508
|
{
|
|
537
|
-
|
|
538
|
-
onClick: () => onPromotionPieceSelect(piece),
|
|
509
|
+
onClick: () => setPromotionMove(null),
|
|
539
510
|
onContextMenu: (e) => {
|
|
540
511
|
e.preventDefault();
|
|
512
|
+
setPromotionMove(null);
|
|
541
513
|
},
|
|
542
514
|
style: {
|
|
543
|
-
|
|
544
|
-
|
|
515
|
+
position: "absolute",
|
|
516
|
+
top: 0,
|
|
517
|
+
left: 0,
|
|
518
|
+
right: 0,
|
|
519
|
+
bottom: 0,
|
|
520
|
+
backgroundColor: "rgba(0, 0, 0, 0.1)",
|
|
521
|
+
zIndex: 1e3
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
), /* @__PURE__ */ React5.createElement(
|
|
525
|
+
"div",
|
|
526
|
+
{
|
|
527
|
+
style: {
|
|
528
|
+
position: "absolute",
|
|
529
|
+
top: ((_b = (_a = promotionMove.to) == null ? void 0 : _a[1]) == null ? void 0 : _b.includes("8")) ? 0 : "auto",
|
|
530
|
+
bottom: ((_c = promotionMove.to) == null ? void 0 : _c[1].includes("1")) ? 0 : "auto",
|
|
531
|
+
left: promotionSquareLeft,
|
|
532
|
+
backgroundColor: "white",
|
|
533
|
+
width: squareWidth,
|
|
534
|
+
zIndex: 1001,
|
|
545
535
|
display: "flex",
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
padding: 0,
|
|
549
|
-
border: "none",
|
|
550
|
-
cursor: "pointer",
|
|
551
|
-
backgroundColor: "white"
|
|
552
|
-
},
|
|
553
|
-
onMouseEnter: (e) => {
|
|
554
|
-
e.currentTarget.style.backgroundColor = "#f0f0f0";
|
|
555
|
-
},
|
|
556
|
-
onMouseLeave: (e) => {
|
|
557
|
-
e.currentTarget.style.backgroundColor = "white";
|
|
536
|
+
flexDirection: "column",
|
|
537
|
+
boxShadow: "0 0 10px 0 rgba(0, 0, 0, 0.5)"
|
|
558
538
|
}
|
|
559
539
|
},
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
540
|
+
["q", "r", "n", "b"].map((piece) => /* @__PURE__ */ React5.createElement(
|
|
541
|
+
"button",
|
|
542
|
+
{
|
|
543
|
+
key: piece,
|
|
544
|
+
onClick: () => onPromotionPieceSelect(piece),
|
|
545
|
+
onContextMenu: (e) => {
|
|
546
|
+
e.preventDefault();
|
|
547
|
+
},
|
|
548
|
+
style: {
|
|
549
|
+
width: "100%",
|
|
550
|
+
aspectRatio: "1",
|
|
551
|
+
display: "flex",
|
|
552
|
+
alignItems: "center",
|
|
553
|
+
justifyContent: "center",
|
|
554
|
+
padding: 0,
|
|
555
|
+
border: "none",
|
|
556
|
+
cursor: "pointer",
|
|
557
|
+
backgroundColor: "white"
|
|
558
|
+
},
|
|
559
|
+
onMouseEnter: (e) => {
|
|
560
|
+
e.currentTarget.style.backgroundColor = "#f0f0f0";
|
|
561
|
+
},
|
|
562
|
+
onMouseLeave: (e) => {
|
|
563
|
+
e.currentTarget.style.backgroundColor = "white";
|
|
564
|
+
}
|
|
565
|
+
},
|
|
566
|
+
defaultPieces[`${turn}${piece.toUpperCase()}`]()
|
|
567
|
+
))
|
|
568
|
+
)));
|
|
569
|
+
}
|
|
570
|
+
);
|
|
571
|
+
Board.displayName = "ChessGame.Board";
|
|
564
572
|
|
|
565
573
|
// src/components/ChessGame/parts/Sounds.tsx
|
|
566
574
|
import { useMemo } from "react";
|
|
@@ -622,6 +630,7 @@ var Sounds = ({ sounds }) => {
|
|
|
622
630
|
useBoardSounds(customSoundsAudios);
|
|
623
631
|
return null;
|
|
624
632
|
};
|
|
633
|
+
Sounds.displayName = "ChessGame.Sounds";
|
|
625
634
|
|
|
626
635
|
// src/hooks/useKeyboardControls.ts
|
|
627
636
|
import { useEffect as useEffect3 } from "react";
|
|
@@ -665,6 +674,7 @@ var KeyboardControls2 = ({
|
|
|
665
674
|
useKeyboardControls(keyboardControls);
|
|
666
675
|
return null;
|
|
667
676
|
};
|
|
677
|
+
KeyboardControls2.displayName = "ChessGame.KeyboardControls";
|
|
668
678
|
|
|
669
679
|
// src/components/ChessGame/index.ts
|
|
670
680
|
var ChessGame = {
|