@react-chess-tools/react-chess-game 0.5.2 → 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.
Files changed (48) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/README.md +399 -0
  3. package/dist/index.cjs +785 -0
  4. package/dist/index.cjs.map +1 -0
  5. package/dist/index.d.cts +278 -0
  6. package/dist/index.d.ts +278 -0
  7. package/dist/{index.mjs → index.js} +339 -196
  8. package/dist/index.js.map +1 -0
  9. package/package.json +19 -9
  10. package/src/components/ChessGame/Theme.stories.tsx +242 -0
  11. package/src/components/ChessGame/ThemePresets.stories.tsx +144 -0
  12. package/src/components/ChessGame/parts/Board.tsx +215 -204
  13. package/src/components/ChessGame/parts/KeyboardControls.tsx +9 -0
  14. package/src/components/ChessGame/parts/Root.tsx +13 -1
  15. package/src/components/ChessGame/parts/Sounds.tsx +9 -0
  16. package/src/components/ChessGame/parts/__tests__/Board.test.tsx +122 -0
  17. package/src/components/ChessGame/parts/__tests__/KeyboardControls.test.tsx +34 -0
  18. package/src/components/ChessGame/parts/__tests__/Root.test.tsx +50 -0
  19. package/src/components/ChessGame/parts/__tests__/Sounds.test.tsx +22 -0
  20. package/src/docs/Theming.mdx +281 -0
  21. package/src/hooks/useChessGame.ts +23 -7
  22. package/src/index.ts +19 -0
  23. package/src/theme/__tests__/context.test.tsx +60 -0
  24. package/src/theme/__tests__/defaults.test.ts +61 -0
  25. package/src/theme/__tests__/utils.test.ts +106 -0
  26. package/src/theme/context.tsx +37 -0
  27. package/src/theme/defaults.ts +22 -0
  28. package/src/theme/index.ts +36 -0
  29. package/src/theme/presets.ts +41 -0
  30. package/src/theme/types.ts +56 -0
  31. package/src/theme/utils.ts +47 -0
  32. package/src/utils/__tests__/board.test.ts +118 -0
  33. package/src/utils/board.ts +18 -9
  34. package/src/utils/chess.ts +25 -5
  35. package/README.MD +0 -190
  36. package/coverage/clover.xml +0 -6
  37. package/coverage/coverage-final.json +0 -1
  38. package/coverage/lcov-report/base.css +0 -224
  39. package/coverage/lcov-report/block-navigation.js +0 -87
  40. package/coverage/lcov-report/favicon.png +0 -0
  41. package/coverage/lcov-report/index.html +0 -101
  42. package/coverage/lcov-report/prettify.css +0 -1
  43. package/coverage/lcov-report/prettify.js +0 -2
  44. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  45. package/coverage/lcov-report/sorter.js +0 -196
  46. package/coverage/lcov.info +0 -0
  47. package/dist/index.d.mts +0 -158
  48. package/dist/index.mjs.map +0 -1
@@ -1,5 +1,5 @@
1
1
  // src/components/ChessGame/parts/Root.tsx
2
- import React3 from "react";
2
+ import React4 from "react";
3
3
 
4
4
  // src/hooks/useChessGame.ts
5
5
  import React, { useEffect } from "react";
@@ -9,9 +9,17 @@ import { Chess as Chess2 } from "chess.js";
9
9
  import { Chess } from "chess.js";
10
10
  import _ from "lodash";
11
11
  var cloneGame = (game) => {
12
- const copy = new Chess();
13
- copy.loadPgn(game.pgn());
14
- return copy;
12
+ try {
13
+ const copy = new Chess();
14
+ const pgn = game == null ? void 0 : game.pgn();
15
+ if (pgn) {
16
+ copy.loadPgn(pgn);
17
+ }
18
+ return copy;
19
+ } catch (e) {
20
+ console.error("Failed to clone game:", e);
21
+ return new Chess();
22
+ }
15
23
  };
16
24
  var getGameInfo = (game, orientation) => {
17
25
  const turn = game.turn();
@@ -57,6 +65,9 @@ var isLegalMove = (game, move) => {
57
65
  }
58
66
  };
59
67
  var requiresPromotion = (game, move) => {
68
+ if (!game) {
69
+ throw new Error("Game is required");
70
+ }
60
71
  try {
61
72
  const copy = cloneGame(game);
62
73
  const result = copy.move(move);
@@ -76,12 +87,20 @@ var getCurrentFen = (fen, game, currentMoveIndex) => {
76
87
  const tempGame = new Chess();
77
88
  if (currentMoveIndex === -1) {
78
89
  if (fen) {
79
- tempGame.load(fen);
90
+ try {
91
+ tempGame.load(fen);
92
+ } catch (e) {
93
+ console.error("Failed to load FEN in getCurrentFen:", fen, e);
94
+ }
80
95
  }
81
96
  } else {
82
97
  const moves = game.history().slice(0, currentMoveIndex + 1);
83
98
  if (fen) {
84
- tempGame.load(fen);
99
+ try {
100
+ tempGame.load(fen);
101
+ } catch (e) {
102
+ console.error("Failed to load FEN in getCurrentFen:", fen, e);
103
+ }
85
104
  }
86
105
  moves.forEach((move) => tempGame.move(move));
87
106
  }
@@ -93,9 +112,21 @@ var useChessGame = ({
93
112
  fen,
94
113
  orientation: initialOrientation
95
114
  } = {}) => {
96
- const [game, setGame] = React.useState(new Chess2(fen));
115
+ const [game, setGame] = React.useState(() => {
116
+ try {
117
+ return new Chess2(fen);
118
+ } catch (e) {
119
+ console.error("Invalid FEN:", fen, e);
120
+ return new Chess2();
121
+ }
122
+ });
97
123
  useEffect(() => {
98
- setGame(new Chess2(fen));
124
+ try {
125
+ setGame(new Chess2(fen));
126
+ } catch (e) {
127
+ console.error("Invalid FEN:", fen, e);
128
+ setGame(new Chess2());
129
+ }
99
130
  }, [fen]);
100
131
  const [orientation, setOrientation] = React.useState(
101
132
  initialOrientation ?? "w"
@@ -119,11 +150,15 @@ var useChessGame = ({
119
150
  [game, currentMoveIndex]
120
151
  );
121
152
  const setPosition = React.useCallback((fen2, orientation2) => {
122
- const newGame = new Chess2();
123
- newGame.load(fen2);
124
- setOrientation(orientation2);
125
- setGame(newGame);
126
- setCurrentMoveIndex(-1);
153
+ try {
154
+ const newGame = new Chess2();
155
+ newGame.load(fen2);
156
+ setOrientation(orientation2);
157
+ setGame(newGame);
158
+ setCurrentMoveIndex(-1);
159
+ } catch (e) {
160
+ console.error("Failed to load FEN:", fen2, e);
161
+ }
127
162
  }, []);
128
163
  const makeMove = React.useCallback(
129
164
  (move) => {
@@ -212,18 +247,69 @@ var useChessGameContext = () => {
212
247
  return context;
213
248
  };
214
249
 
250
+ // src/theme/context.tsx
251
+ import React3, { createContext, useContext } from "react";
252
+
253
+ // src/theme/defaults.ts
254
+ var defaultGameTheme = {
255
+ board: {
256
+ lightSquare: { backgroundColor: "#f0d9b5" },
257
+ darkSquare: { backgroundColor: "#b58863" }
258
+ },
259
+ state: {
260
+ lastMove: "rgba(255, 255, 0, 0.5)",
261
+ check: "rgba(255, 0, 0, 0.5)",
262
+ activeSquare: "rgba(255, 255, 0, 0.5)",
263
+ dropSquare: { backgroundColor: "rgba(255, 255, 0, 0.4)" }
264
+ },
265
+ indicators: {
266
+ move: "rgba(0, 0, 0, 0.1)",
267
+ capture: "rgba(1, 0, 0, 0.1)"
268
+ }
269
+ };
270
+
271
+ // src/theme/context.tsx
272
+ var ChessGameThemeContext = createContext(defaultGameTheme);
273
+ var useChessGameTheme = () => {
274
+ return useContext(ChessGameThemeContext);
275
+ };
276
+ var ThemeProvider = ({
277
+ theme,
278
+ children
279
+ }) => {
280
+ return /* @__PURE__ */ React3.createElement(ChessGameThemeContext.Provider, { value: theme }, children);
281
+ };
282
+
283
+ // src/theme/utils.ts
284
+ import { merge } from "lodash";
285
+ var mergeTheme = (partialTheme) => {
286
+ if (!partialTheme) {
287
+ return { ...defaultGameTheme };
288
+ }
289
+ return merge({}, defaultGameTheme, partialTheme);
290
+ };
291
+ var mergeThemeWith = (baseTheme, partialTheme) => {
292
+ if (!partialTheme) {
293
+ return { ...baseTheme };
294
+ }
295
+ return merge({}, baseTheme, partialTheme);
296
+ };
297
+
215
298
  // src/components/ChessGame/parts/Root.tsx
216
299
  var Root = ({
217
300
  fen,
218
301
  orientation,
302
+ theme,
219
303
  children
220
304
  }) => {
221
305
  const context = useChessGame({ fen, orientation });
222
- return /* @__PURE__ */ React3.createElement(ChessGameContext.Provider, { value: context }, children);
306
+ const mergedTheme = React4.useMemo(() => mergeTheme(theme), [theme]);
307
+ return /* @__PURE__ */ React4.createElement(ChessGameContext.Provider, { value: context }, /* @__PURE__ */ React4.createElement(ThemeProvider, { theme: mergedTheme }, children));
223
308
  };
309
+ Root.displayName = "ChessGame.Root";
224
310
 
225
311
  // src/components/ChessGame/parts/Board.tsx
226
- import React4 from "react";
312
+ import React5 from "react";
227
313
  import {
228
314
  Chessboard,
229
315
  defaultPieces,
@@ -231,23 +317,21 @@ import {
231
317
  } from "react-chessboard";
232
318
 
233
319
  // src/utils/board.ts
234
- import { merge } from "lodash";
235
- var LAST_MOVE_COLOR = "rgba(255, 255, 0, 0.5)";
236
- var CHECK_COLOR = "rgba(255, 0, 0, 0.5)";
237
- var getCustomSquareStyles = (game, info, activeSquare) => {
320
+ import { merge as merge2 } from "lodash";
321
+ var getCustomSquareStyles = (game, info, activeSquare, theme = defaultGameTheme) => {
238
322
  const customSquareStyles = {};
239
323
  const { lastMove, isCheck, turn } = info;
240
324
  if (lastMove) {
241
325
  customSquareStyles[lastMove.from] = {
242
- backgroundColor: LAST_MOVE_COLOR
326
+ backgroundColor: theme.state.lastMove
243
327
  };
244
328
  customSquareStyles[lastMove.to] = {
245
- backgroundColor: LAST_MOVE_COLOR
329
+ backgroundColor: theme.state.lastMove
246
330
  };
247
331
  }
248
332
  if (activeSquare) {
249
333
  customSquareStyles[activeSquare] = {
250
- backgroundColor: LAST_MOVE_COLOR
334
+ backgroundColor: theme.state.activeSquare
251
335
  };
252
336
  }
253
337
  if (activeSquare) {
@@ -255,7 +339,7 @@ var getCustomSquareStyles = (game, info, activeSquare) => {
255
339
  destinationSquares.forEach((square) => {
256
340
  var _a;
257
341
  customSquareStyles[square] = {
258
- background: game.get(square) && ((_a = game.get(square)) == null ? void 0 : _a.color) !== turn ? "radial-gradient(circle, rgba(1, 0, 0, 0.1) 85%, transparent 85%)" : "radial-gradient(circle, rgba(0,0,0,.1) 25%, transparent 25%)"
342
+ background: game.get(square) && ((_a = game.get(square)) == null ? void 0 : _a.color) !== turn ? `radial-gradient(circle, ${theme.indicators.capture} 85%, transparent 85%)` : `radial-gradient(circle, ${theme.indicators.move} 25%, transparent 25%)`
259
343
  };
260
344
  });
261
345
  }
@@ -264,7 +348,7 @@ var getCustomSquareStyles = (game, info, activeSquare) => {
264
348
  return row.forEach((square) => {
265
349
  if ((square == null ? void 0 : square.type) === "k" && (square == null ? void 0 : square.color) === info.turn) {
266
350
  customSquareStyles[square.square] = {
267
- backgroundColor: CHECK_COLOR
351
+ backgroundColor: theme.state.check
268
352
  };
269
353
  }
270
354
  });
@@ -276,7 +360,7 @@ var deepMergeChessboardOptions = (baseOptions, customOptions) => {
276
360
  if (!customOptions) {
277
361
  return { ...baseOptions };
278
362
  }
279
- const result = merge({}, baseOptions, customOptions, {
363
+ const result = merge2({}, baseOptions, customOptions, {
280
364
  customizer: (_objValue, srcValue) => {
281
365
  if (typeof srcValue === "function") {
282
366
  return srcValue;
@@ -292,191 +376,199 @@ var deepMergeChessboardOptions = (baseOptions, customOptions) => {
292
376
  };
293
377
 
294
378
  // src/components/ChessGame/parts/Board.tsx
295
- var Board = ({ options = {} }) => {
296
- var _a, _b, _c;
297
- const gameContext = useChessGameContext();
298
- if (!gameContext) {
299
- throw new Error("ChessGameContext not found");
300
- }
301
- const {
302
- game,
303
- currentFen,
304
- orientation,
305
- info,
306
- isLatestMove,
307
- methods: { makeMove }
308
- } = gameContext;
309
- const { turn, isGameOver } = info;
310
- const [activeSquare, setActiveSquare] = React4.useState(null);
311
- const [promotionMove, setPromotionMove] = React4.useState(null);
312
- const onSquareClick = (square) => {
313
- if (isGameOver) {
314
- 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");
315
386
  }
316
- if (activeSquare === null) {
317
- const squadreInfo = game.get(square);
318
- if (squadreInfo && squadreInfo.color === turn) {
319
- return setActiveSquare(square);
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;
320
401
  }
321
- return;
322
- }
323
- if (!isLegalMove(game, {
324
- from: activeSquare,
325
- to: square,
326
- promotion: "q"
327
- })) {
328
- return setActiveSquare(null);
329
- }
330
- if (requiresPromotion(game, {
331
- from: activeSquare,
332
- to: square,
333
- promotion: "q"
334
- })) {
335
- 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, {
336
410
  from: activeSquare,
337
- to: square
338
- });
339
- }
340
- setActiveSquare(null);
341
- makeMove({
342
- from: activeSquare,
343
- to: square
344
- });
345
- };
346
- const onPromotionPieceSelect = (piece) => {
347
- if ((promotionMove == null ? void 0 : promotionMove.from) && (promotionMove == null ? void 0 : promotionMove.to)) {
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);
348
427
  makeMove({
349
- from: promotionMove.from,
350
- to: promotionMove.to,
351
- promotion: piece.toLowerCase()
428
+ from: activeSquare,
429
+ to: square
352
430
  });
353
- setPromotionMove(null);
354
- }
355
- };
356
- const onSquareRightClick = () => {
357
- setActiveSquare(null);
358
- setPromotionMove(null);
359
- };
360
- const squareWidth = React4.useMemo(() => {
361
- var _a2;
362
- if (typeof document === "undefined") return 80;
363
- const squareElement = document.querySelector(`[data-square]`);
364
- return ((_a2 = squareElement == null ? void 0 : squareElement.getBoundingClientRect()) == null ? void 0 : _a2.width) ?? 80;
365
- }, [promotionMove]);
366
- const promotionSquareLeft = React4.useMemo(() => {
367
- var _a2;
368
- if (!(promotionMove == null ? void 0 : promotionMove.to)) return 0;
369
- const column = ((_a2 = promotionMove.to.match(/^[a-h]/)) == null ? void 0 : _a2[0]) ?? "a";
370
- return squareWidth * chessColumnToColumnIndex(
371
- column,
372
- 8,
373
- orientation === "b" ? "black" : "white"
374
- );
375
- }, [promotionMove, squareWidth, orientation]);
376
- const baseOptions = {
377
- squareStyles: getCustomSquareStyles(game, info, activeSquare),
378
- boardOrientation: orientation === "b" ? "black" : "white",
379
- position: currentFen,
380
- showNotation: true,
381
- showAnimations: isLatestMove,
382
- canDragPiece: ({ piece }) => {
383
- if (isGameOver) return false;
384
- return piece.pieceType[0] === turn;
385
- },
386
- dropSquareStyle: {
387
- backgroundColor: "rgba(255, 255, 0, 0.4)"
388
- },
389
- onPieceDrag: ({ piece, square }) => {
390
- if (piece.pieceType[0] === turn) {
391
- 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);
392
440
  }
393
- },
394
- onPieceDrop: ({ sourceSquare, targetSquare }) => {
441
+ };
442
+ const onSquareRightClick = () => {
395
443
  setActiveSquare(null);
396
- const moveData = {
397
- from: sourceSquare,
398
- to: targetSquare
399
- };
400
- if (requiresPromotion(game, { ...moveData, promotion: "q" })) {
401
- setPromotionMove(moveData);
402
- return false;
403
- }
404
- return makeMove(moveData);
405
- },
406
- onSquareClick: ({ square }) => {
407
- if (square.match(/^[a-h][1-8]$/)) {
408
- onSquareClick(square);
409
- }
410
- },
411
- onSquareRightClick,
412
- allowDrawingArrows: true,
413
- animationDurationInMs: game.history().length === 0 ? 0 : 300
414
- };
415
- const mergedOptions = deepMergeChessboardOptions(baseOptions, options);
416
- return /* @__PURE__ */ React4.createElement("div", { style: { position: "relative" } }, /* @__PURE__ */ React4.createElement(Chessboard, { options: mergedOptions }), promotionMove && /* @__PURE__ */ React4.createElement(React4.Fragment, null, /* @__PURE__ */ React4.createElement(
417
- "div",
418
- {
419
- onClick: () => setPromotionMove(null),
420
- onContextMenu: (e) => {
421
- e.preventDefault();
422
- setPromotionMove(null);
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;
423
473
  },
424
- style: {
425
- position: "absolute",
426
- top: 0,
427
- left: 0,
428
- right: 0,
429
- bottom: 0,
430
- backgroundColor: "rgba(0, 0, 0, 0.1)",
431
- zIndex: 1e3
432
- }
433
- }
434
- ), /* @__PURE__ */ React4.createElement(
435
- "div",
436
- {
437
- style: {
438
- position: "absolute",
439
- top: ((_b = (_a = promotionMove.to) == null ? void 0 : _a[1]) == null ? void 0 : _b.includes("8")) ? 0 : "auto",
440
- bottom: ((_c = promotionMove.to) == null ? void 0 : _c[1].includes("1")) ? 0 : "auto",
441
- left: promotionSquareLeft,
442
- backgroundColor: "white",
443
- width: squareWidth,
444
- zIndex: 1001,
445
- display: "flex",
446
- flexDirection: "column",
447
- boxShadow: "0 0 10px 0 rgba(0, 0, 0, 0.5)"
448
- }
449
- },
450
- ["q", "r", "n", "b"].map((piece) => /* @__PURE__ */ React4.createElement(
451
- "button",
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",
452
508
  {
453
- key: piece,
454
- onClick: () => onPromotionPieceSelect(piece),
509
+ onClick: () => setPromotionMove(null),
455
510
  onContextMenu: (e) => {
456
511
  e.preventDefault();
512
+ setPromotionMove(null);
457
513
  },
458
514
  style: {
459
- width: "100%",
460
- aspectRatio: "1",
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,
461
535
  display: "flex",
462
- alignItems: "center",
463
- justifyContent: "center",
464
- padding: 0,
465
- border: "none",
466
- cursor: "pointer",
467
- backgroundColor: "white"
468
- },
469
- onMouseEnter: (e) => {
470
- e.currentTarget.style.backgroundColor = "#f0f0f0";
471
- },
472
- onMouseLeave: (e) => {
473
- e.currentTarget.style.backgroundColor = "white";
536
+ flexDirection: "column",
537
+ boxShadow: "0 0 10px 0 rgba(0, 0, 0, 0.5)"
474
538
  }
475
539
  },
476
- defaultPieces[`${turn}${piece.toUpperCase()}`]()
477
- ))
478
- )));
479
- };
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";
480
572
 
481
573
  // src/components/ChessGame/parts/Sounds.tsx
482
574
  import { useMemo } from "react";
@@ -538,6 +630,7 @@ var Sounds = ({ sounds }) => {
538
630
  useBoardSounds(customSoundsAudios);
539
631
  return null;
540
632
  };
633
+ Sounds.displayName = "ChessGame.Sounds";
541
634
 
542
635
  // src/hooks/useKeyboardControls.ts
543
636
  import { useEffect as useEffect3 } from "react";
@@ -581,6 +674,7 @@ var KeyboardControls2 = ({
581
674
  useKeyboardControls(keyboardControls);
582
675
  return null;
583
676
  };
677
+ KeyboardControls2.displayName = "ChessGame.KeyboardControls";
584
678
 
585
679
  // src/components/ChessGame/index.ts
586
680
  var ChessGame = {
@@ -589,10 +683,59 @@ var ChessGame = {
589
683
  Sounds,
590
684
  KeyboardControls: KeyboardControls2
591
685
  };
686
+
687
+ // src/theme/presets.ts
688
+ var lichessTheme = {
689
+ board: {
690
+ lightSquare: { backgroundColor: "#f0d9b5" },
691
+ darkSquare: { backgroundColor: "#b58863" }
692
+ },
693
+ state: {
694
+ lastMove: "rgba(155, 199, 0, 0.41)",
695
+ check: "rgba(255, 0, 0, 0.5)",
696
+ activeSquare: "rgba(20, 85, 30, 0.5)",
697
+ dropSquare: { backgroundColor: "rgba(20, 85, 30, 0.3)" }
698
+ },
699
+ indicators: {
700
+ move: "rgba(20, 85, 30, 0.3)",
701
+ capture: "rgba(20, 85, 30, 0.3)"
702
+ }
703
+ };
704
+ var chessComTheme = {
705
+ board: {
706
+ lightSquare: { backgroundColor: "#ebecd0" },
707
+ darkSquare: { backgroundColor: "#779556" }
708
+ },
709
+ state: {
710
+ lastMove: "rgba(255, 255, 0, 0.5)",
711
+ check: "rgba(255, 0, 0, 0.7)",
712
+ activeSquare: "rgba(255, 255, 0, 0.5)",
713
+ dropSquare: { backgroundColor: "rgba(255, 255, 0, 0.4)" }
714
+ },
715
+ indicators: {
716
+ move: "rgba(0, 0, 0, 0.1)",
717
+ capture: "rgba(0, 0, 0, 0.1)"
718
+ }
719
+ };
720
+
721
+ // src/theme/index.ts
722
+ var themes = {
723
+ default: defaultGameTheme,
724
+ lichess: lichessTheme,
725
+ chessCom: chessComTheme
726
+ };
592
727
  export {
593
728
  ChessGame,
729
+ ChessGameThemeContext,
730
+ chessComTheme,
594
731
  deepMergeChessboardOptions,
732
+ defaultGameTheme,
733
+ lichessTheme,
734
+ mergeTheme,
735
+ mergeThemeWith,
736
+ themes,
595
737
  useChessGame,
596
- useChessGameContext
738
+ useChessGameContext,
739
+ useChessGameTheme
597
740
  };
598
- //# sourceMappingURL=index.mjs.map
741
+ //# sourceMappingURL=index.js.map