@react-chess-tools/react-chess-game 1.0.1 → 1.0.2

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/dist/index.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import React4 from "react";
3
3
 
4
4
  // src/hooks/useChessGame.ts
5
- import React, { useEffect } from "react";
5
+ import React, { useEffect, useRef } from "react";
6
6
  import { Chess as Chess2 } from "chess.js";
7
7
 
8
8
  // src/utils/chess.ts
@@ -108,9 +108,12 @@ var getCurrentFen = (fen, game, currentMoveIndex) => {
108
108
  };
109
109
 
110
110
  // src/hooks/useChessGame.ts
111
+ import { useOptionalChessClock } from "@react-chess-tools/react-chess-clock";
111
112
  var useChessGame = ({
112
113
  fen,
113
- orientation: initialOrientation
114
+ orientation: initialOrientation,
115
+ timeControl,
116
+ autoSwitchOnMove = true
114
117
  } = {}) => {
115
118
  const [game, setGame] = React.useState(() => {
116
119
  try {
@@ -133,22 +136,19 @@ var useChessGame = ({
133
136
  );
134
137
  const [currentMoveIndex, setCurrentMoveIndex] = React.useState(-1);
135
138
  const history = React.useMemo(() => game.history(), [game]);
136
- const isLatestMove = React.useMemo(
137
- () => currentMoveIndex === history.length - 1 || currentMoveIndex === -1,
138
- [currentMoveIndex, history.length]
139
- );
139
+ const isLatestMove = currentMoveIndex === history.length - 1 || currentMoveIndex === -1;
140
140
  const info = React.useMemo(
141
141
  () => getGameInfo(game, orientation),
142
142
  [game, orientation]
143
143
  );
144
144
  const currentFen = React.useMemo(
145
145
  () => getCurrentFen(fen, game, currentMoveIndex),
146
- [game, currentMoveIndex]
147
- );
148
- const currentPosition = React.useMemo(
149
- () => game.history()[currentMoveIndex],
150
- [game, currentMoveIndex]
146
+ [fen, game, currentMoveIndex]
151
147
  );
148
+ const currentPosition = game.history()[currentMoveIndex];
149
+ const clockState = useOptionalChessClock(timeControl);
150
+ const clockStateRef = useRef(clockState);
151
+ clockStateRef.current = clockState;
152
152
  const setPosition = React.useCallback((fen2, orientation2) => {
153
153
  try {
154
154
  const newGame = new Chess2();
@@ -165,17 +165,30 @@ var useChessGame = ({
165
165
  if (!isLatestMove) {
166
166
  return false;
167
167
  }
168
+ const clock = clockStateRef.current;
169
+ if (clock && clock.timeout !== null) {
170
+ return false;
171
+ }
168
172
  try {
169
173
  const copy = cloneGame(game);
170
174
  copy.move(move);
171
175
  setGame(copy);
172
176
  setCurrentMoveIndex(copy.history().length - 1);
177
+ if (clock && clock.status === "idle") {
178
+ clock.methods.start();
179
+ }
180
+ if (clock && clock.status === "running" && copy.isGameOver()) {
181
+ clock.methods.pause();
182
+ }
183
+ if (autoSwitchOnMove && clock && clock.status !== "finished") {
184
+ clock.methods.switch();
185
+ }
173
186
  return true;
174
187
  } catch (e) {
175
188
  return false;
176
189
  }
177
190
  },
178
- [isLatestMove, game]
191
+ [isLatestMove, game, autoSwitchOnMove]
179
192
  );
180
193
  const flipBoard = React.useCallback(() => {
181
194
  setOrientation((orientation2) => orientation2 === "w" ? "b" : "w");
@@ -230,7 +243,8 @@ var useChessGame = ({
230
243
  currentMoveIndex,
231
244
  isLatestMove,
232
245
  info,
233
- methods
246
+ methods,
247
+ clock: clockState
234
248
  };
235
249
  };
236
250
 
@@ -300,9 +314,16 @@ var Root = ({
300
314
  fen,
301
315
  orientation,
302
316
  theme,
317
+ timeControl,
318
+ autoSwitchOnMove,
303
319
  children
304
320
  }) => {
305
- const context = useChessGame({ fen, orientation });
321
+ const context = useChessGame({
322
+ fen,
323
+ orientation,
324
+ timeControl,
325
+ autoSwitchOnMove
326
+ });
306
327
  const mergedTheme = React4.useMemo(() => mergeTheme(theme), [theme]);
307
328
  return /* @__PURE__ */ React4.createElement(ChessGameContext.Provider, { value: context }, /* @__PURE__ */ React4.createElement(ThemeProvider, { theme: mergedTheme }, children));
308
329
  };
@@ -676,14 +697,68 @@ var KeyboardControls2 = ({
676
697
  };
677
698
  KeyboardControls2.displayName = "ChessGame.KeyboardControls";
678
699
 
700
+ // src/components/ChessGame/Clock/index.tsx
701
+ import React6 from "react";
702
+ import {
703
+ Display as ClockDisplay,
704
+ Switch as ClockSwitch,
705
+ PlayPause as ClockPlayPause,
706
+ Reset as ClockReset,
707
+ ChessClockContext
708
+ } from "@react-chess-tools/react-chess-clock";
709
+ var Display = React6.forwardRef(
710
+ ({ color, ...rest }, ref) => {
711
+ const { clock } = useChessGameContext();
712
+ if (!clock) {
713
+ return null;
714
+ }
715
+ return /* @__PURE__ */ React6.createElement(ChessClockContext.Provider, { value: clock }, /* @__PURE__ */ React6.createElement(ClockDisplay, { ref, color, ...rest }));
716
+ }
717
+ );
718
+ Display.displayName = "ChessGame.Clock.Display";
719
+ var Switch = React6.forwardRef(({ children, ...rest }, ref) => {
720
+ const { clock } = useChessGameContext();
721
+ if (!clock) {
722
+ return null;
723
+ }
724
+ return /* @__PURE__ */ React6.createElement(ChessClockContext.Provider, { value: clock }, /* @__PURE__ */ React6.createElement(ClockSwitch, { ref, ...rest }, children));
725
+ });
726
+ Switch.displayName = "ChessGame.Clock.Switch";
727
+ var PlayPause = React6.forwardRef(({ children, ...rest }, ref) => {
728
+ const { clock } = useChessGameContext();
729
+ if (!clock) {
730
+ return null;
731
+ }
732
+ return /* @__PURE__ */ React6.createElement(ChessClockContext.Provider, { value: clock }, /* @__PURE__ */ React6.createElement(ClockPlayPause, { ref, ...rest }, children));
733
+ });
734
+ PlayPause.displayName = "ChessGame.Clock.PlayPause";
735
+ var Reset = React6.forwardRef(({ children, ...rest }, ref) => {
736
+ const { clock } = useChessGameContext();
737
+ if (!clock) {
738
+ return null;
739
+ }
740
+ return /* @__PURE__ */ React6.createElement(ChessClockContext.Provider, { value: clock }, /* @__PURE__ */ React6.createElement(ClockReset, { ref, ...rest }, children));
741
+ });
742
+ Reset.displayName = "ChessGame.Clock.Reset";
743
+ var Clock = {
744
+ Display,
745
+ Switch,
746
+ PlayPause,
747
+ Reset
748
+ };
749
+
679
750
  // src/components/ChessGame/index.ts
680
751
  var ChessGame = {
681
752
  Root,
682
753
  Board,
683
754
  Sounds,
684
- KeyboardControls: KeyboardControls2
755
+ KeyboardControls: KeyboardControls2,
756
+ Clock
685
757
  };
686
758
 
759
+ // src/index.ts
760
+ import { ChessClock } from "@react-chess-tools/react-chess-clock";
761
+
687
762
  // src/theme/presets.ts
688
763
  var lichessTheme = {
689
764
  board: {
@@ -725,6 +800,7 @@ var themes = {
725
800
  chessCom: chessComTheme
726
801
  };
727
802
  export {
803
+ ChessClock,
728
804
  ChessGame,
729
805
  ChessGameThemeContext,
730
806
  chessComTheme,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/ChessGame/parts/Root.tsx","../src/hooks/useChessGame.ts","../src/utils/chess.ts","../src/hooks/useChessGameContext.ts","../src/theme/context.tsx","../src/theme/defaults.ts","../src/theme/utils.ts","../src/components/ChessGame/parts/Board.tsx","../src/utils/board.ts","../src/components/ChessGame/parts/Sounds.tsx","../src/assets/sounds.ts","../src/hooks/useBoardSounds.ts","../src/hooks/useKeyboardControls.ts","../src/components/ChessGame/parts/KeyboardControls.tsx","../src/components/ChessGame/index.ts","../src/theme/presets.ts","../src/theme/index.ts"],"sourcesContent":["import React from \"react\";\nimport { Color } from \"chess.js\";\nimport { useChessGame } from \"../../../hooks/useChessGame\";\nimport { ChessGameContext } from \"../../../hooks/useChessGameContext\";\nimport { ThemeProvider } from \"../../../theme/context\";\nimport { mergeTheme } from \"../../../theme/utils\";\nimport type { PartialChessGameTheme } from \"../../../theme/types\";\n\nexport interface RootProps {\n fen?: string;\n orientation?: Color;\n /** Optional theme configuration. Supports partial themes - only override the colors you need. */\n theme?: PartialChessGameTheme;\n}\n\nexport const Root: React.FC<React.PropsWithChildren<RootProps>> = ({\n fen,\n orientation,\n theme,\n children,\n}) => {\n const context = useChessGame({ fen, orientation });\n\n // Merge partial theme with defaults\n const mergedTheme = React.useMemo(() => mergeTheme(theme), [theme]);\n\n return (\n <ChessGameContext.Provider value={context}>\n <ThemeProvider theme={mergedTheme}>{children}</ThemeProvider>\n </ChessGameContext.Provider>\n );\n};\n\nRoot.displayName = \"ChessGame.Root\";\n","import React, { useEffect } from \"react\";\nimport { Chess, Color } from \"chess.js\";\nimport { cloneGame, getCurrentFen, getGameInfo } from \"../utils/chess\";\n\nexport type useChessGameProps = {\n fen?: string;\n orientation?: Color;\n};\n\nexport const useChessGame = ({\n fen,\n orientation: initialOrientation,\n}: useChessGameProps = {}) => {\n const [game, setGame] = React.useState(() => {\n try {\n return new Chess(fen);\n } catch (e) {\n console.error(\"Invalid FEN:\", fen, e);\n return new Chess(); // Return empty board\n }\n });\n\n useEffect(() => {\n try {\n setGame(new Chess(fen));\n } catch (e) {\n console.error(\"Invalid FEN:\", fen, e);\n setGame(new Chess());\n }\n }, [fen]);\n\n const [orientation, setOrientation] = React.useState<Color>(\n initialOrientation ?? \"w\",\n );\n const [currentMoveIndex, setCurrentMoveIndex] = React.useState(-1);\n\n const history = React.useMemo(() => game.history(), [game]);\n const isLatestMove = React.useMemo(\n () => currentMoveIndex === history.length - 1 || currentMoveIndex === -1,\n [currentMoveIndex, history.length],\n );\n\n const info = React.useMemo(\n () => getGameInfo(game, orientation),\n [game, orientation],\n );\n\n const currentFen = React.useMemo(\n () => getCurrentFen(fen, game, currentMoveIndex),\n [game, currentMoveIndex],\n );\n\n const currentPosition = React.useMemo(\n () => game.history()[currentMoveIndex],\n [game, currentMoveIndex],\n );\n\n const setPosition = React.useCallback((fen: string, orientation: Color) => {\n try {\n const newGame = new Chess();\n newGame.load(fen);\n setOrientation(orientation);\n setGame(newGame);\n setCurrentMoveIndex(-1);\n } catch (e) {\n console.error(\"Failed to load FEN:\", fen, e);\n }\n }, []);\n\n const makeMove = React.useCallback(\n (move: Parameters<Chess[\"move\"]>[0]): boolean => {\n // Only allow moves when we're at the latest position\n if (!isLatestMove) {\n return false;\n }\n\n try {\n const copy = cloneGame(game);\n copy.move(move);\n setGame(copy);\n setCurrentMoveIndex(copy.history().length - 1);\n return true;\n } catch (e) {\n return false;\n }\n },\n [isLatestMove, game],\n );\n\n const flipBoard = React.useCallback(() => {\n setOrientation((orientation) => (orientation === \"w\" ? \"b\" : \"w\"));\n }, []);\n\n const goToMove = React.useCallback(\n (moveIndex: number) => {\n if (moveIndex < -1 || moveIndex >= history.length) return;\n setCurrentMoveIndex(moveIndex);\n },\n [history.length],\n );\n\n const goToStart = React.useCallback(() => goToMove(-1), []);\n const goToEnd = React.useCallback(\n () => goToMove(history.length - 1),\n [history.length],\n );\n const goToPreviousMove = React.useCallback(\n () => goToMove(currentMoveIndex - 1),\n [currentMoveIndex],\n );\n const goToNextMove = React.useCallback(\n () => goToMove(currentMoveIndex + 1),\n [currentMoveIndex],\n );\n\n const methods = React.useMemo(\n () => ({\n makeMove,\n setPosition,\n flipBoard,\n goToMove,\n goToStart,\n goToEnd,\n goToPreviousMove,\n goToNextMove,\n }),\n [\n makeMove,\n setPosition,\n flipBoard,\n goToMove,\n goToStart,\n goToEnd,\n goToPreviousMove,\n goToNextMove,\n ],\n );\n\n return {\n game,\n currentFen,\n currentPosition,\n orientation,\n currentMoveIndex,\n isLatestMove,\n info,\n methods,\n };\n};\n","import { Chess, Color, Square } from \"chess.js\";\nimport _ from \"lodash\";\n\n/**\n * Creates a clone of the given Chess.js instance. This is needed to update the state\n * of react-chessboard component\n * @param game - The Chess.js instance to clone.\n * @returns A new Chess.js instance with the same state as the original.\n */\nexport const cloneGame = (game: Chess) => {\n try {\n const copy = new Chess();\n const pgn = game?.pgn();\n if (pgn) {\n copy.loadPgn(pgn);\n }\n return copy;\n } catch (e) {\n console.error(\"Failed to clone game:\", e);\n return new Chess();\n }\n};\n\n/**\n * Returns an object with information about the current state of the game. This can be determined\n * using chess.js instance, but this function is provided for convenience.\n * @param game - The Chess.js instance representing the game.\n * @returns An object with information about the current state of the game.\n */\n\nexport const getGameInfo = (game: Chess, orientation: Color) => {\n const turn = game.turn();\n const isPlayerTurn = turn === orientation;\n const isOpponentTurn = !isPlayerTurn;\n const moveNumber = game.history().length;\n const lastMove = _.last(game.history({ verbose: true }));\n const isCheck = game.isCheck();\n const isCheckmate = game.isCheckmate();\n const isDraw = game.isDraw();\n const isStalemate = game.isStalemate();\n const isThreefoldRepetition = game.isThreefoldRepetition();\n const isInsufficientMaterial = game.isInsufficientMaterial();\n const isGameOver = game.isGameOver();\n const hasPlayerWon = isOpponentTurn && isGameOver && !isDraw;\n const hasPlayerLost = isPlayerTurn && isGameOver && !isDraw;\n const isDrawn = game.isDraw();\n return {\n turn,\n isPlayerTurn,\n isOpponentTurn,\n moveNumber,\n lastMove,\n isCheck,\n isCheckmate,\n isDraw,\n isStalemate,\n isThreefoldRepetition,\n isInsufficientMaterial,\n isGameOver,\n isDrawn,\n hasPlayerWon,\n hasPlayerLost,\n };\n};\n\nexport type GameInfo = ReturnType<typeof getGameInfo>;\n\nexport const isLegalMove = (\n game: Chess,\n move: Parameters<Chess[\"move\"]>[0],\n) => {\n try {\n const copy = cloneGame(game);\n copy.move(move);\n return true;\n } catch (e) {\n return false;\n }\n};\n\nexport const requiresPromotion = (\n game: Chess,\n move: Parameters<Chess[\"move\"]>[0],\n) => {\n if (!game) {\n throw new Error(\"Game is required\");\n }\n\n try {\n const copy = cloneGame(game);\n const result = copy.move(move);\n\n return result.flags.indexOf(\"p\") !== -1;\n } catch (e) {\n if (e instanceof Error && e.message.includes(\"Invalid move\")) {\n return false;\n }\n throw e;\n }\n};\n\nexport const getDestinationSquares = (game: Chess, square: Square) => {\n const moves = game.moves({ square, verbose: true });\n return moves.map((move) => move.to);\n};\n\nexport const getCurrentFen = (\n fen: string | undefined,\n game: Chess,\n currentMoveIndex: number,\n) => {\n const tempGame = new Chess();\n if (currentMoveIndex === -1) {\n if (fen) {\n try {\n tempGame.load(fen);\n } catch (e) {\n console.error(\"Failed to load FEN in getCurrentFen:\", fen, e);\n }\n }\n } else {\n const moves = game.history().slice(0, currentMoveIndex + 1);\n\n if (fen) {\n try {\n tempGame.load(fen);\n } catch (e) {\n console.error(\"Failed to load FEN in getCurrentFen:\", fen, e);\n }\n }\n moves.forEach((move) => tempGame.move(move));\n }\n return tempGame.fen();\n};\n","import React from \"react\";\nimport { useChessGame } from \"./useChessGame\";\n\nexport const ChessGameContext = React.createContext<ReturnType<\n typeof useChessGame\n> | null>(null);\n\nexport const useChessGameContext = () => {\n const context = React.useContext(ChessGameContext);\n if (!context) {\n throw new Error(\n `useChessGameContext must be used within a ChessGame component. Make sure your component is wrapped with <ChessGame.Root> or ensure the ChessGame component is properly rendered in the component tree.`,\n );\n }\n return context;\n};\n\nexport type ChessGameContextType = ReturnType<typeof useChessGame>;\n","import React, { createContext, useContext } from \"react\";\nimport type { ChessGameTheme } from \"./types\";\nimport { defaultGameTheme } from \"./defaults\";\n\n/**\n * Context for ChessGame theme\n */\nexport const ChessGameThemeContext =\n createContext<ChessGameTheme>(defaultGameTheme);\n\n/**\n * Hook to access the current ChessGame theme.\n * Returns the default theme if no ThemeProvider is present.\n */\nexport const useChessGameTheme = (): ChessGameTheme => {\n return useContext(ChessGameThemeContext);\n};\n\nexport interface ThemeProviderProps {\n theme: ChessGameTheme;\n children: React.ReactNode;\n}\n\n/**\n * Internal provider component used by Root when a theme prop is provided.\n * This is not exported directly - users pass theme via Root's theme prop.\n */\nexport const ThemeProvider: React.FC<ThemeProviderProps> = ({\n theme,\n children,\n}) => {\n return (\n <ChessGameThemeContext.Provider value={theme}>\n {children}\n </ChessGameThemeContext.Provider>\n );\n};\n","import type { ChessGameTheme } from \"./types\";\n\n/**\n * Default theme for ChessGame component.\n * These values match the original hardcoded colors for backward compatibility.\n */\nexport const defaultGameTheme: ChessGameTheme = {\n board: {\n lightSquare: { backgroundColor: \"#f0d9b5\" },\n darkSquare: { backgroundColor: \"#b58863\" },\n },\n state: {\n lastMove: \"rgba(255, 255, 0, 0.5)\",\n check: \"rgba(255, 0, 0, 0.5)\",\n activeSquare: \"rgba(255, 255, 0, 0.5)\",\n dropSquare: { backgroundColor: \"rgba(255, 255, 0, 0.4)\" },\n },\n indicators: {\n move: \"rgba(0, 0, 0, 0.1)\",\n capture: \"rgba(1, 0, 0, 0.1)\",\n },\n};\n","import { merge } from \"lodash\";\nimport type { ChessGameTheme, PartialChessGameTheme } from \"./types\";\nimport { defaultGameTheme } from \"./defaults\";\n\n/**\n * Deep merges a partial theme with the default theme.\n * Allows users to override only specific theme properties while keeping defaults for the rest.\n *\n * @param partialTheme - Partial theme with only the properties to override\n * @returns Complete theme with overridden properties merged with defaults\n *\n * @example\n * ```typescript\n * const customTheme = mergeTheme({\n * state: { lastMove: \"rgba(100, 200, 100, 0.6)\" }\n * });\n * // Returns full theme with only lastMove color changed\n * ```\n */\nexport const mergeTheme = (\n partialTheme?: PartialChessGameTheme,\n): ChessGameTheme => {\n if (!partialTheme) {\n return { ...defaultGameTheme };\n }\n\n return merge({}, defaultGameTheme, partialTheme);\n};\n\n/**\n * Deep merges a partial theme with a base theme.\n * Useful when extending an existing theme.\n *\n * @param baseTheme - The base theme to extend\n * @param partialTheme - Partial theme with properties to override\n * @returns Complete theme with overridden properties\n */\nexport const mergeThemeWith = (\n baseTheme: ChessGameTheme,\n partialTheme?: PartialChessGameTheme,\n): ChessGameTheme => {\n if (!partialTheme) {\n return { ...baseTheme };\n }\n\n return merge({}, baseTheme, partialTheme);\n};\n","import React from \"react\";\nimport {\n Chessboard,\n ChessboardOptions,\n defaultPieces,\n chessColumnToColumnIndex,\n} from \"react-chessboard\";\nimport { Move, Square } from \"chess.js\";\nimport {\n getCustomSquareStyles,\n deepMergeChessboardOptions,\n} from \"../../../utils/board\";\nimport { isLegalMove, requiresPromotion } from \"../../../utils/chess\";\nimport { useChessGameContext } from \"../../../hooks/useChessGameContext\";\nimport { useChessGameTheme } from \"../../../theme/context\";\n\nexport interface ChessGameProps extends React.HTMLAttributes<HTMLDivElement> {\n options?: ChessboardOptions;\n}\n\nexport const Board = React.forwardRef<HTMLDivElement, ChessGameProps>(\n ({ options = {}, className, style: userStyle, ...rest }, ref) => {\n const gameContext = useChessGameContext();\n const theme = useChessGameTheme();\n\n if (!gameContext) {\n throw new Error(\"ChessGameContext not found\");\n }\n\n const {\n game,\n currentFen,\n orientation,\n info,\n isLatestMove,\n methods: { makeMove },\n } = gameContext;\n\n const { turn, isGameOver } = info;\n\n const [activeSquare, setActiveSquare] = React.useState<Square | null>(null);\n\n const [promotionMove, setPromotionMove] =\n React.useState<Partial<Move> | null>(null);\n\n const onSquareClick = (square: Square) => {\n if (isGameOver) {\n return;\n }\n\n if (activeSquare === null) {\n const squadreInfo = game.get(square);\n if (squadreInfo && squadreInfo.color === turn) {\n return setActiveSquare(square);\n }\n return;\n }\n\n if (\n !isLegalMove(game, {\n from: activeSquare,\n to: square,\n promotion: \"q\",\n })\n ) {\n return setActiveSquare(null);\n }\n\n if (\n requiresPromotion(game, {\n from: activeSquare,\n to: square,\n promotion: \"q\",\n })\n ) {\n return setPromotionMove({\n from: activeSquare,\n to: square,\n });\n }\n\n setActiveSquare(null);\n makeMove({\n from: activeSquare,\n to: square,\n });\n };\n\n const onPromotionPieceSelect = (piece: string): void => {\n if (promotionMove?.from && promotionMove?.to) {\n makeMove({\n from: promotionMove.from,\n to: promotionMove.to,\n promotion: piece.toLowerCase(),\n });\n setPromotionMove(null);\n }\n };\n\n const onSquareRightClick = () => {\n setActiveSquare(null);\n setPromotionMove(null);\n };\n\n // Calculate square width for precise positioning\n const squareWidth = React.useMemo(() => {\n if (typeof document === \"undefined\") return 80;\n const squareElement = document.querySelector(`[data-square]`);\n return squareElement?.getBoundingClientRect()?.width ?? 80;\n }, [promotionMove]);\n\n // Calculate promotion square position\n const promotionSquareLeft = React.useMemo(() => {\n if (!promotionMove?.to) return 0;\n const column = promotionMove.to.match(/^[a-h]/)?.[0] ?? \"a\";\n return (\n squareWidth *\n chessColumnToColumnIndex(\n column,\n 8,\n orientation === \"b\" ? \"black\" : \"white\",\n )\n );\n }, [promotionMove, squareWidth, orientation]);\n\n const baseOptions: ChessboardOptions = {\n squareStyles: getCustomSquareStyles(game, info, activeSquare, theme),\n boardOrientation: orientation === \"b\" ? \"black\" : \"white\",\n position: currentFen,\n showNotation: true,\n showAnimations: isLatestMove,\n lightSquareStyle: theme.board.lightSquare,\n darkSquareStyle: theme.board.darkSquare,\n canDragPiece: ({ piece }) => {\n if (isGameOver) return false;\n return piece.pieceType[0] === turn;\n },\n dropSquareStyle: theme.state.dropSquare,\n onPieceDrag: ({ piece, square }) => {\n if (piece.pieceType[0] === turn) {\n setActiveSquare(square as Square);\n }\n },\n onPieceDrop: ({ sourceSquare, targetSquare }) => {\n setActiveSquare(null);\n const moveData = {\n from: sourceSquare as Square,\n to: targetSquare as Square,\n };\n\n // Check if promotion is needed\n if (requiresPromotion(game, { ...moveData, promotion: \"q\" })) {\n setPromotionMove(moveData);\n return false; // Prevent the move until promotion is selected\n }\n\n return makeMove(moveData);\n },\n onSquareClick: ({ square }) => {\n if (square.match(/^[a-h][1-8]$/)) {\n onSquareClick(square as Square);\n }\n },\n onSquareRightClick: onSquareRightClick,\n allowDrawingArrows: true,\n animationDurationInMs: game.history().length === 0 ? 0 : 300,\n };\n\n const mergedOptions = deepMergeChessboardOptions(baseOptions, options);\n\n const mergedStyle = {\n ...userStyle,\n position: \"relative\" as const,\n };\n\n return (\n <div ref={ref} className={className} style={mergedStyle} {...rest}>\n <Chessboard options={mergedOptions} />\n {promotionMove && (\n <>\n {/* Backdrop overlay - click to cancel */}\n <div\n onClick={() => setPromotionMove(null)}\n onContextMenu={(e) => {\n e.preventDefault();\n setPromotionMove(null);\n }}\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n backgroundColor: \"rgba(0, 0, 0, 0.1)\",\n zIndex: 1000,\n }}\n />\n {/* Promotion piece selection */}\n <div\n style={{\n position: \"absolute\",\n top: promotionMove.to?.[1]?.includes(\"8\") ? 0 : \"auto\",\n bottom: promotionMove.to?.[1].includes(\"1\") ? 0 : \"auto\",\n left: promotionSquareLeft,\n backgroundColor: \"white\",\n width: squareWidth,\n zIndex: 1001,\n display: \"flex\",\n flexDirection: \"column\",\n boxShadow: \"0 0 10px 0 rgba(0, 0, 0, 0.5)\",\n }}\n >\n {[\"q\", \"r\", \"n\", \"b\"].map((piece) => (\n <button\n key={piece}\n onClick={() => onPromotionPieceSelect(piece)}\n onContextMenu={(e) => {\n e.preventDefault();\n }}\n style={{\n width: \"100%\",\n aspectRatio: \"1\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n padding: 0,\n border: \"none\",\n cursor: \"pointer\",\n backgroundColor: \"white\",\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.backgroundColor = \"#f0f0f0\";\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = \"white\";\n }}\n >\n {defaultPieces[\n `${turn}${piece.toUpperCase()}` as keyof typeof defaultPieces\n ]()}\n </button>\n ))}\n </div>\n </>\n )}\n </div>\n );\n },\n);\n\nBoard.displayName = \"ChessGame.Board\";\n","import { type Chess, type Square } from \"chess.js\";\nimport { type CSSProperties } from \"react\";\nimport { merge } from \"lodash\";\nimport type { ChessboardOptions } from \"react-chessboard\";\nimport { getDestinationSquares, type GameInfo } from \"./chess\";\nimport type { ChessGameTheme } from \"../theme/types\";\nimport { defaultGameTheme } from \"../theme/defaults\";\n\n/**\n * Generates custom square styles based on game state and theme.\n *\n * @param game - Chess.js game instance\n * @param info - Game info containing lastMove, isCheck, turn\n * @param activeSquare - Currently selected square (if any)\n * @param theme - Theme configuration (defaults to defaultGameTheme)\n * @returns Record of square names to CSS properties\n */\nexport const getCustomSquareStyles = (\n game: Chess,\n info: GameInfo,\n activeSquare: Square | null,\n theme: ChessGameTheme = defaultGameTheme,\n) => {\n const customSquareStyles: Record<string, CSSProperties> = {};\n\n const { lastMove, isCheck, turn } = info;\n\n if (lastMove) {\n customSquareStyles[lastMove.from] = {\n backgroundColor: theme.state.lastMove,\n };\n customSquareStyles[lastMove.to] = {\n backgroundColor: theme.state.lastMove,\n };\n }\n\n if (activeSquare) {\n customSquareStyles[activeSquare] = {\n backgroundColor: theme.state.activeSquare,\n };\n }\n\n if (activeSquare) {\n const destinationSquares = getDestinationSquares(game, activeSquare);\n destinationSquares.forEach((square) => {\n customSquareStyles[square] = {\n background:\n game.get(square) && game.get(square)?.color !== turn\n ? `radial-gradient(circle, ${theme.indicators.capture} 85%, transparent 85%)`\n : `radial-gradient(circle, ${theme.indicators.move} 25%, transparent 25%)`,\n };\n });\n }\n\n if (isCheck) {\n game.board().forEach((row) => {\n return row.forEach((square) => {\n if (square?.type === \"k\" && square?.color === info.turn) {\n customSquareStyles[square.square] = {\n backgroundColor: theme.state.check,\n };\n }\n });\n });\n }\n return customSquareStyles;\n};\n\n/**\n * Smart deep merge for ChessboardOptions that handles different property types appropriately:\n * - Functions: Overwrite (custom functions replace base functions)\n * - Objects: Deep merge (nested objects merge recursively)\n * - Primitives: Overwrite (custom values replace base values)\n *\n * This ensures that computed options (like squareStyles with move highlighting) are preserved\n * while allowing custom options to extend or override them intelligently.\n *\n * @param baseOptions - The computed base options (e.g., computed squareStyles, event handlers)\n * @param customOptions - Custom options provided by the user\n * @returns Intelligently merged ChessboardOptions\n */\nexport const deepMergeChessboardOptions = (\n baseOptions: ChessboardOptions,\n customOptions?: Partial<ChessboardOptions>,\n): ChessboardOptions => {\n if (!customOptions) {\n return { ...baseOptions }; // Return a new object even when no custom options\n }\n\n const result = merge({}, baseOptions, customOptions, {\n customizer: (_objValue: unknown, srcValue: unknown) => {\n // Functions should always overwrite (not merge)\n // This is important for event handlers like onSquareClick, onPieceDrop, etc.\n if (typeof srcValue === \"function\") {\n return srcValue;\n }\n\n // For arrays, we typically want to overwrite rather than merge\n // This avoids unexpected behavior with array concatenation\n if (Array.isArray(srcValue)) {\n return srcValue;\n }\n\n // Let lodash handle objects with default deep merge behavior\n // This will properly merge nested objects like squareStyles, dropSquareStyle, etc.\n return undefined; // Use default merge behavior\n },\n });\n\n // Clean up any unwanted properties that lodash might add\n delete (result as Record<string, unknown>).customizer;\n\n return result;\n};\n","import { useMemo } from \"react\";\nimport { defaultSounds, type Sound } from \"../../../assets/sounds\";\nimport { useBoardSounds } from \"../../../hooks/useBoardSounds\";\n\n/**\n * Props for the Sounds component\n *\n * Note: This is a logic-only component that returns null and does not render\n * any DOM elements. It sets up board sounds via the useBoardSounds hook.\n * Therefore, it does not accept HTML attributes like className, style, etc.\n */\nexport type SoundsProps = {\n sounds?: Partial<Record<Sound, string>>;\n};\n\nexport const Sounds: React.FC<SoundsProps> = ({ sounds }) => {\n const customSoundsAudios = useMemo(() => {\n if (typeof window === \"undefined\" || typeof Audio === \"undefined\") {\n return {} as Record<Sound, HTMLAudioElement>;\n }\n\n return Object.entries({ ...defaultSounds, sounds }).reduce(\n (acc, [name, base64]) => {\n acc[name as Sound] = new Audio(`data:audio/wav;base64,${base64}`);\n return acc;\n },\n {} as Record<Sound, HTMLAudioElement>,\n );\n }, [sounds]);\n useBoardSounds(customSoundsAudios);\n return null;\n};\n\nSounds.displayName = \"ChessGame.Sounds\";\n","export type Sound = \"check\" | \"move\" | \"capture\" | \"gameOver\";\nexport type Sounds = Record<Sound, HTMLAudioElement>;\n\nconst SILENCE = \"Li4vU2lsZW5jZS5vZ2c=\";\n\nexport const defaultSounds: Record<Sound, string> = {\n move: \"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\",\n capture:\n \"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\",\n check: SILENCE,\n gameOver:\n \"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\",\n};\n","import { useEffect } from \"react\";\nimport { useChessGameContext } from \"./useChessGameContext\";\nimport { type Sound } from \"../assets/sounds\";\n\nconst playSound = async (audioElement: HTMLAudioElement) => {\n try {\n await audioElement.play();\n } catch (error) {\n console.warn(\"Failed to play sound:\", (error as Error).message);\n }\n};\n\nexport const useBoardSounds = (sounds: Record<Sound, HTMLAudioElement>) => {\n const {\n info: { lastMove, isCheckmate },\n } = useChessGameContext();\n\n useEffect(() => {\n if (Object.keys(sounds).length === 0) {\n return;\n }\n\n if (isCheckmate && sounds.gameOver) {\n playSound(sounds.gameOver);\n return;\n }\n\n if (lastMove?.captured && sounds.capture) {\n playSound(sounds.capture);\n return;\n }\n\n if (lastMove && sounds.move) {\n playSound(sounds.move);\n }\n }, [lastMove]);\n};\n","import { useEffect } from \"react\";\nimport {\n defaultKeyboardControls,\n KeyboardControls,\n} from \"../components/ChessGame/parts/KeyboardControls\";\nimport { useChessGameContext } from \"./useChessGameContext\";\n\nexport const useKeyboardControls = (controls?: KeyboardControls) => {\n const gameContext = useChessGameContext();\n if (!gameContext) {\n throw new Error(\"ChessGameContext not found\");\n }\n const keyboardControls = { ...defaultKeyboardControls, ...controls };\n useEffect(() => {\n const handleKeyDown = (event: KeyboardEvent) => {\n const handler = keyboardControls[event.key];\n if (handler) {\n event.preventDefault();\n handler(gameContext);\n }\n };\n window.addEventListener(\"keydown\", handleKeyDown);\n return () => {\n window.removeEventListener(\"keydown\", handleKeyDown);\n };\n }, [gameContext]);\n return null;\n};\n","import {\n ChessGameContextType,\n useChessGameContext,\n} from \"../../../hooks/useChessGameContext\";\nimport { useKeyboardControls } from \"../../../hooks/useKeyboardControls\";\n\nexport type KeyboardControls = Record<\n string,\n (context: ChessGameContextType) => void\n>;\n\nexport const defaultKeyboardControls: KeyboardControls = {\n ArrowLeft: (context) => context.methods.goToPreviousMove(),\n ArrowRight: (context) => context.methods.goToNextMove(),\n ArrowUp: (context) => context.methods.goToStart(),\n ArrowDown: (context) => context.methods.goToEnd(),\n};\n\n/**\n * Props for the KeyboardControls component\n *\n * Note: This is a logic-only component that returns null and does not render\n * any DOM elements. It sets up keyboard controls via the useKeyboardControls hook.\n * Therefore, it does not accept HTML attributes like className, style, etc.\n */\ntype KeyboardControlsProps = {\n controls?: KeyboardControls;\n};\n\nexport const KeyboardControls: React.FC<KeyboardControlsProps> = ({\n controls,\n}) => {\n const gameContext = useChessGameContext();\n if (!gameContext) {\n throw new Error(\"ChessGameContext not found\");\n }\n const keyboardControls = { ...defaultKeyboardControls, ...controls };\n useKeyboardControls(keyboardControls);\n return null;\n};\n\nKeyboardControls.displayName = \"ChessGame.KeyboardControls\";\n","import { Root } from \"./parts/Root\";\nimport { Board } from \"./parts/Board\";\nimport { Sounds } from \"./parts/Sounds\";\nimport { KeyboardControls } from \"./parts/KeyboardControls\";\n\nexport const ChessGame = {\n Root,\n Board,\n Sounds,\n KeyboardControls,\n};\n","import type { ChessGameTheme } from \"./types\";\n\n/**\n * Lichess-inspired theme with green highlights\n */\nexport const lichessTheme: ChessGameTheme = {\n board: {\n lightSquare: { backgroundColor: \"#f0d9b5\" },\n darkSquare: { backgroundColor: \"#b58863\" },\n },\n state: {\n lastMove: \"rgba(155, 199, 0, 0.41)\",\n check: \"rgba(255, 0, 0, 0.5)\",\n activeSquare: \"rgba(20, 85, 30, 0.5)\",\n dropSquare: { backgroundColor: \"rgba(20, 85, 30, 0.3)\" },\n },\n indicators: {\n move: \"rgba(20, 85, 30, 0.3)\",\n capture: \"rgba(20, 85, 30, 0.3)\",\n },\n};\n\n/**\n * Chess.com-inspired theme with green board and yellow highlights\n */\nexport const chessComTheme: ChessGameTheme = {\n board: {\n lightSquare: { backgroundColor: \"#ebecd0\" },\n darkSquare: { backgroundColor: \"#779556\" },\n },\n state: {\n lastMove: \"rgba(255, 255, 0, 0.5)\",\n check: \"rgba(255, 0, 0, 0.7)\",\n activeSquare: \"rgba(255, 255, 0, 0.5)\",\n dropSquare: { backgroundColor: \"rgba(255, 255, 0, 0.4)\" },\n },\n indicators: {\n move: \"rgba(0, 0, 0, 0.1)\",\n capture: \"rgba(0, 0, 0, 0.1)\",\n },\n};\n","// Types\nexport type {\n ChessGameTheme,\n BoardTheme,\n StateTheme,\n IndicatorTheme,\n PartialChessGameTheme,\n DeepPartial,\n} from \"./types\";\n\n// Default theme\nexport { defaultGameTheme } from \"./defaults\";\n\n// Preset themes\nexport { lichessTheme, chessComTheme } from \"./presets\";\n\n// All themes as a single object\nimport { defaultGameTheme } from \"./defaults\";\nimport { lichessTheme, chessComTheme } from \"./presets\";\n\nexport const themes = {\n default: defaultGameTheme,\n lichess: lichessTheme,\n chessCom: chessComTheme,\n} as const;\n\n// Utilities\nexport { mergeTheme, mergeThemeWith } from \"./utils\";\n\n// Context and hook\nexport {\n ChessGameThemeContext,\n useChessGameTheme,\n ThemeProvider,\n} from \"./context\";\nexport type { ThemeProviderProps } from \"./context\";\n"],"mappings":"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","names":["React","Chess","Chess","fen","orientation","React","React","React","React","React","merge","merge","React","_a","useEffect","useEffect","useEffect","useEffect","KeyboardControls","KeyboardControls"]}
1
+ {"version":3,"sources":["../src/components/ChessGame/parts/Root.tsx","../src/hooks/useChessGame.ts","../src/utils/chess.ts","../src/hooks/useChessGameContext.ts","../src/theme/context.tsx","../src/theme/defaults.ts","../src/theme/utils.ts","../src/components/ChessGame/parts/Board.tsx","../src/utils/board.ts","../src/components/ChessGame/parts/Sounds.tsx","../src/assets/sounds.ts","../src/hooks/useBoardSounds.ts","../src/hooks/useKeyboardControls.ts","../src/components/ChessGame/parts/KeyboardControls.tsx","../src/components/ChessGame/Clock/index.tsx","../src/components/ChessGame/index.ts","../src/index.ts","../src/theme/presets.ts","../src/theme/index.ts"],"sourcesContent":["import React from \"react\";\nimport { Color } from \"chess.js\";\nimport { useChessGame } from \"../../../hooks/useChessGame\";\nimport { ChessGameContext } from \"../../../hooks/useChessGameContext\";\nimport { ThemeProvider } from \"../../../theme/context\";\nimport { mergeTheme } from \"../../../theme/utils\";\nimport type { PartialChessGameTheme } from \"../../../theme/types\";\nimport type { TimeControlConfig } from \"@react-chess-tools/react-chess-clock\";\n\nexport interface RootProps {\n fen?: string;\n orientation?: Color;\n /** Optional theme configuration. Supports partial themes - only override the colors you need. */\n theme?: PartialChessGameTheme;\n /** Optional clock configuration to enable chess clock functionality */\n timeControl?: TimeControlConfig;\n /** Auto-switch clock on move (default: true) */\n autoSwitchOnMove?: boolean;\n}\n\nexport const Root: React.FC<React.PropsWithChildren<RootProps>> = ({\n fen,\n orientation,\n theme,\n timeControl,\n autoSwitchOnMove,\n children,\n}) => {\n const context = useChessGame({\n fen,\n orientation,\n timeControl,\n autoSwitchOnMove,\n });\n\n // Merge partial theme with defaults\n const mergedTheme = React.useMemo(() => mergeTheme(theme), [theme]);\n\n return (\n <ChessGameContext.Provider value={context}>\n <ThemeProvider theme={mergedTheme}>{children}</ThemeProvider>\n </ChessGameContext.Provider>\n );\n};\n\nRoot.displayName = \"ChessGame.Root\";\n","import React, { useEffect, useRef } from \"react\";\nimport { Chess, Color } from \"chess.js\";\nimport { cloneGame, getCurrentFen, getGameInfo } from \"../utils/chess\";\nimport { useOptionalChessClock } from \"@react-chess-tools/react-chess-clock\";\nimport type { TimeControlConfig } from \"@react-chess-tools/react-chess-clock\";\n\nexport type useChessGameProps = {\n fen?: string;\n orientation?: Color;\n /** Optional clock configuration to enable chess clock functionality */\n timeControl?: TimeControlConfig;\n /** Automatically switch the clock after each move (default: true).\n * Set to false to let players manually press the clock, mimicking real-life over-the-board play. */\n autoSwitchOnMove?: boolean;\n};\n\nexport const useChessGame = ({\n fen,\n orientation: initialOrientation,\n timeControl,\n autoSwitchOnMove = true,\n}: useChessGameProps = {}) => {\n const [game, setGame] = React.useState(() => {\n try {\n return new Chess(fen);\n } catch (e) {\n console.error(\"Invalid FEN:\", fen, e);\n return new Chess();\n }\n });\n\n useEffect(() => {\n try {\n setGame(new Chess(fen));\n } catch (e) {\n console.error(\"Invalid FEN:\", fen, e);\n setGame(new Chess());\n }\n }, [fen]);\n\n const [orientation, setOrientation] = React.useState<Color>(\n initialOrientation ?? \"w\",\n );\n const [currentMoveIndex, setCurrentMoveIndex] = React.useState(-1);\n\n const history = React.useMemo(() => game.history(), [game]);\n const isLatestMove =\n currentMoveIndex === history.length - 1 || currentMoveIndex === -1;\n\n const info = React.useMemo(\n () => getGameInfo(game, orientation),\n [game, orientation],\n );\n\n const currentFen = React.useMemo(\n () => getCurrentFen(fen, game, currentMoveIndex),\n [fen, game, currentMoveIndex],\n );\n\n const currentPosition = game.history()[currentMoveIndex];\n\n const clockState = useOptionalChessClock(timeControl);\n\n // Keep clockState in a ref to avoid re-creating makeMove on every clock tick.\n // The clock state object is recreated on every render (especially during active\n // ticking), which would defeat the useCallback memoization.\n const clockStateRef = useRef(clockState);\n clockStateRef.current = clockState;\n\n const setPosition = React.useCallback((fen: string, orientation: Color) => {\n try {\n const newGame = new Chess();\n newGame.load(fen);\n setOrientation(orientation);\n setGame(newGame);\n setCurrentMoveIndex(-1);\n } catch (e) {\n console.error(\"Failed to load FEN:\", fen, e);\n }\n }, []);\n\n const makeMove = React.useCallback(\n (move: Parameters<Chess[\"move\"]>[0]): boolean => {\n // Only allow moves when we're at the latest position\n if (!isLatestMove) {\n return false;\n }\n\n // Access clock state via ref to avoid stale closures while keeping\n // the callback stable (not re-created on every clock tick)\n const clock = clockStateRef.current;\n\n // Don't allow moves after clock timeout\n if (clock && clock.timeout !== null) {\n return false;\n }\n\n try {\n const copy = cloneGame(game);\n copy.move(move);\n setGame(copy);\n setCurrentMoveIndex(copy.history().length - 1);\n\n // Auto-start clock on first move\n if (clock && clock.status === \"idle\") {\n clock.methods.start();\n }\n\n // Pause clock on game over (checked immediately after move)\n if (clock && clock.status === \"running\" && copy.isGameOver()) {\n clock.methods.pause();\n }\n\n // Auto-switch clock after a move is made if enabled\n if (autoSwitchOnMove && clock && clock.status !== \"finished\") {\n clock.methods.switch();\n }\n\n return true;\n } catch (e) {\n return false;\n }\n },\n [isLatestMove, game, autoSwitchOnMove],\n );\n\n const flipBoard = React.useCallback(() => {\n setOrientation((orientation) => (orientation === \"w\" ? \"b\" : \"w\"));\n }, []);\n\n const goToMove = React.useCallback(\n (moveIndex: number) => {\n if (moveIndex < -1 || moveIndex >= history.length) return;\n setCurrentMoveIndex(moveIndex);\n },\n [history.length],\n );\n\n const goToStart = React.useCallback(() => goToMove(-1), []);\n const goToEnd = React.useCallback(\n () => goToMove(history.length - 1),\n [history.length],\n );\n const goToPreviousMove = React.useCallback(\n () => goToMove(currentMoveIndex - 1),\n [currentMoveIndex],\n );\n const goToNextMove = React.useCallback(\n () => goToMove(currentMoveIndex + 1),\n [currentMoveIndex],\n );\n\n const methods = React.useMemo(\n () => ({\n makeMove,\n setPosition,\n flipBoard,\n goToMove,\n goToStart,\n goToEnd,\n goToPreviousMove,\n goToNextMove,\n }),\n [\n makeMove,\n setPosition,\n flipBoard,\n goToMove,\n goToStart,\n goToEnd,\n goToPreviousMove,\n goToNextMove,\n ],\n );\n\n return {\n game,\n currentFen,\n currentPosition,\n orientation,\n currentMoveIndex,\n isLatestMove,\n info,\n methods,\n clock: clockState,\n };\n};\n","import { Chess, Color, Square } from \"chess.js\";\nimport _ from \"lodash\";\n\n/**\n * Creates a clone of the given Chess.js instance. This is needed to update the state\n * of react-chessboard component\n * @param game - The Chess.js instance to clone.\n * @returns A new Chess.js instance with the same state as the original.\n */\nexport const cloneGame = (game: Chess) => {\n try {\n const copy = new Chess();\n const pgn = game?.pgn();\n if (pgn) {\n copy.loadPgn(pgn);\n }\n return copy;\n } catch (e) {\n console.error(\"Failed to clone game:\", e);\n return new Chess();\n }\n};\n\n/**\n * Returns an object with information about the current state of the game. This can be determined\n * using chess.js instance, but this function is provided for convenience.\n * @param game - The Chess.js instance representing the game.\n * @returns An object with information about the current state of the game.\n */\n\nexport const getGameInfo = (game: Chess, orientation: Color) => {\n const turn = game.turn();\n const isPlayerTurn = turn === orientation;\n const isOpponentTurn = !isPlayerTurn;\n const moveNumber = game.history().length;\n const lastMove = _.last(game.history({ verbose: true }));\n const isCheck = game.isCheck();\n const isCheckmate = game.isCheckmate();\n const isDraw = game.isDraw();\n const isStalemate = game.isStalemate();\n const isThreefoldRepetition = game.isThreefoldRepetition();\n const isInsufficientMaterial = game.isInsufficientMaterial();\n const isGameOver = game.isGameOver();\n const hasPlayerWon = isOpponentTurn && isGameOver && !isDraw;\n const hasPlayerLost = isPlayerTurn && isGameOver && !isDraw;\n const isDrawn = game.isDraw();\n return {\n turn,\n isPlayerTurn,\n isOpponentTurn,\n moveNumber,\n lastMove,\n isCheck,\n isCheckmate,\n isDraw,\n isStalemate,\n isThreefoldRepetition,\n isInsufficientMaterial,\n isGameOver,\n isDrawn,\n hasPlayerWon,\n hasPlayerLost,\n };\n};\n\nexport type GameInfo = ReturnType<typeof getGameInfo>;\n\nexport const isLegalMove = (\n game: Chess,\n move: Parameters<Chess[\"move\"]>[0],\n) => {\n try {\n const copy = cloneGame(game);\n copy.move(move);\n return true;\n } catch (e) {\n return false;\n }\n};\n\nexport const requiresPromotion = (\n game: Chess,\n move: Parameters<Chess[\"move\"]>[0],\n) => {\n if (!game) {\n throw new Error(\"Game is required\");\n }\n\n try {\n const copy = cloneGame(game);\n const result = copy.move(move);\n\n return result.flags.indexOf(\"p\") !== -1;\n } catch (e) {\n if (e instanceof Error && e.message.includes(\"Invalid move\")) {\n return false;\n }\n throw e;\n }\n};\n\nexport const getDestinationSquares = (game: Chess, square: Square) => {\n const moves = game.moves({ square, verbose: true });\n return moves.map((move) => move.to);\n};\n\nexport const getCurrentFen = (\n fen: string | undefined,\n game: Chess,\n currentMoveIndex: number,\n) => {\n const tempGame = new Chess();\n if (currentMoveIndex === -1) {\n if (fen) {\n try {\n tempGame.load(fen);\n } catch (e) {\n console.error(\"Failed to load FEN in getCurrentFen:\", fen, e);\n }\n }\n } else {\n const moves = game.history().slice(0, currentMoveIndex + 1);\n\n if (fen) {\n try {\n tempGame.load(fen);\n } catch (e) {\n console.error(\"Failed to load FEN in getCurrentFen:\", fen, e);\n }\n }\n moves.forEach((move) => tempGame.move(move));\n }\n return tempGame.fen();\n};\n","import React from \"react\";\nimport { useChessGame } from \"./useChessGame\";\n\nexport const ChessGameContext = React.createContext<ReturnType<\n typeof useChessGame\n> | null>(null);\n\nexport const useChessGameContext = () => {\n const context = React.useContext(ChessGameContext);\n if (!context) {\n throw new Error(\n `useChessGameContext must be used within a ChessGame component. Make sure your component is wrapped with <ChessGame.Root> or ensure the ChessGame component is properly rendered in the component tree.`,\n );\n }\n return context;\n};\n\nexport type ChessGameContextType = ReturnType<typeof useChessGame>;\n","import React, { createContext, useContext } from \"react\";\nimport type { ChessGameTheme } from \"./types\";\nimport { defaultGameTheme } from \"./defaults\";\n\n/**\n * Context for ChessGame theme\n */\nexport const ChessGameThemeContext =\n createContext<ChessGameTheme>(defaultGameTheme);\n\n/**\n * Hook to access the current ChessGame theme.\n * Returns the default theme if no ThemeProvider is present.\n */\nexport const useChessGameTheme = (): ChessGameTheme => {\n return useContext(ChessGameThemeContext);\n};\n\nexport interface ThemeProviderProps {\n theme: ChessGameTheme;\n children: React.ReactNode;\n}\n\n/**\n * Internal provider component used by Root when a theme prop is provided.\n * This is not exported directly - users pass theme via Root's theme prop.\n */\nexport const ThemeProvider: React.FC<ThemeProviderProps> = ({\n theme,\n children,\n}) => {\n return (\n <ChessGameThemeContext.Provider value={theme}>\n {children}\n </ChessGameThemeContext.Provider>\n );\n};\n","import type { ChessGameTheme } from \"./types\";\n\n/**\n * Default theme for ChessGame component.\n * These values match the original hardcoded colors for backward compatibility.\n */\nexport const defaultGameTheme: ChessGameTheme = {\n board: {\n lightSquare: { backgroundColor: \"#f0d9b5\" },\n darkSquare: { backgroundColor: \"#b58863\" },\n },\n state: {\n lastMove: \"rgba(255, 255, 0, 0.5)\",\n check: \"rgba(255, 0, 0, 0.5)\",\n activeSquare: \"rgba(255, 255, 0, 0.5)\",\n dropSquare: { backgroundColor: \"rgba(255, 255, 0, 0.4)\" },\n },\n indicators: {\n move: \"rgba(0, 0, 0, 0.1)\",\n capture: \"rgba(1, 0, 0, 0.1)\",\n },\n};\n","import { merge } from \"lodash\";\nimport type { ChessGameTheme, PartialChessGameTheme } from \"./types\";\nimport { defaultGameTheme } from \"./defaults\";\n\n/**\n * Deep merges a partial theme with the default theme.\n * Allows users to override only specific theme properties while keeping defaults for the rest.\n *\n * @param partialTheme - Partial theme with only the properties to override\n * @returns Complete theme with overridden properties merged with defaults\n *\n * @example\n * ```typescript\n * const customTheme = mergeTheme({\n * state: { lastMove: \"rgba(100, 200, 100, 0.6)\" }\n * });\n * // Returns full theme with only lastMove color changed\n * ```\n */\nexport const mergeTheme = (\n partialTheme?: PartialChessGameTheme,\n): ChessGameTheme => {\n if (!partialTheme) {\n return { ...defaultGameTheme };\n }\n\n return merge({}, defaultGameTheme, partialTheme);\n};\n\n/**\n * Deep merges a partial theme with a base theme.\n * Useful when extending an existing theme.\n *\n * @param baseTheme - The base theme to extend\n * @param partialTheme - Partial theme with properties to override\n * @returns Complete theme with overridden properties\n */\nexport const mergeThemeWith = (\n baseTheme: ChessGameTheme,\n partialTheme?: PartialChessGameTheme,\n): ChessGameTheme => {\n if (!partialTheme) {\n return { ...baseTheme };\n }\n\n return merge({}, baseTheme, partialTheme);\n};\n","import React from \"react\";\nimport {\n Chessboard,\n ChessboardOptions,\n defaultPieces,\n chessColumnToColumnIndex,\n} from \"react-chessboard\";\nimport { Move, Square } from \"chess.js\";\nimport {\n getCustomSquareStyles,\n deepMergeChessboardOptions,\n} from \"../../../utils/board\";\nimport { isLegalMove, requiresPromotion } from \"../../../utils/chess\";\nimport { useChessGameContext } from \"../../../hooks/useChessGameContext\";\nimport { useChessGameTheme } from \"../../../theme/context\";\n\nexport interface ChessGameProps extends React.HTMLAttributes<HTMLDivElement> {\n options?: ChessboardOptions;\n}\n\nexport const Board = React.forwardRef<HTMLDivElement, ChessGameProps>(\n ({ options = {}, className, style: userStyle, ...rest }, ref) => {\n const gameContext = useChessGameContext();\n const theme = useChessGameTheme();\n\n if (!gameContext) {\n throw new Error(\"ChessGameContext not found\");\n }\n\n const {\n game,\n currentFen,\n orientation,\n info,\n isLatestMove,\n methods: { makeMove },\n } = gameContext;\n\n const { turn, isGameOver } = info;\n\n const [activeSquare, setActiveSquare] = React.useState<Square | null>(null);\n\n const [promotionMove, setPromotionMove] =\n React.useState<Partial<Move> | null>(null);\n\n const onSquareClick = (square: Square) => {\n if (isGameOver) {\n return;\n }\n\n if (activeSquare === null) {\n const squadreInfo = game.get(square);\n if (squadreInfo && squadreInfo.color === turn) {\n return setActiveSquare(square);\n }\n return;\n }\n\n if (\n !isLegalMove(game, {\n from: activeSquare,\n to: square,\n promotion: \"q\",\n })\n ) {\n return setActiveSquare(null);\n }\n\n if (\n requiresPromotion(game, {\n from: activeSquare,\n to: square,\n promotion: \"q\",\n })\n ) {\n return setPromotionMove({\n from: activeSquare,\n to: square,\n });\n }\n\n setActiveSquare(null);\n makeMove({\n from: activeSquare,\n to: square,\n });\n };\n\n const onPromotionPieceSelect = (piece: string): void => {\n if (promotionMove?.from && promotionMove?.to) {\n makeMove({\n from: promotionMove.from,\n to: promotionMove.to,\n promotion: piece.toLowerCase(),\n });\n setPromotionMove(null);\n }\n };\n\n const onSquareRightClick = () => {\n setActiveSquare(null);\n setPromotionMove(null);\n };\n\n // Calculate square width for precise positioning\n const squareWidth = React.useMemo(() => {\n if (typeof document === \"undefined\") return 80;\n const squareElement = document.querySelector(`[data-square]`);\n return squareElement?.getBoundingClientRect()?.width ?? 80;\n }, [promotionMove]);\n\n // Calculate promotion square position\n const promotionSquareLeft = React.useMemo(() => {\n if (!promotionMove?.to) return 0;\n const column = promotionMove.to.match(/^[a-h]/)?.[0] ?? \"a\";\n return (\n squareWidth *\n chessColumnToColumnIndex(\n column,\n 8,\n orientation === \"b\" ? \"black\" : \"white\",\n )\n );\n }, [promotionMove, squareWidth, orientation]);\n\n const baseOptions: ChessboardOptions = {\n squareStyles: getCustomSquareStyles(game, info, activeSquare, theme),\n boardOrientation: orientation === \"b\" ? \"black\" : \"white\",\n position: currentFen,\n showNotation: true,\n showAnimations: isLatestMove,\n lightSquareStyle: theme.board.lightSquare,\n darkSquareStyle: theme.board.darkSquare,\n canDragPiece: ({ piece }) => {\n if (isGameOver) return false;\n return piece.pieceType[0] === turn;\n },\n dropSquareStyle: theme.state.dropSquare,\n onPieceDrag: ({ piece, square }) => {\n if (piece.pieceType[0] === turn) {\n setActiveSquare(square as Square);\n }\n },\n onPieceDrop: ({ sourceSquare, targetSquare }) => {\n setActiveSquare(null);\n const moveData = {\n from: sourceSquare as Square,\n to: targetSquare as Square,\n };\n\n // Check if promotion is needed\n if (requiresPromotion(game, { ...moveData, promotion: \"q\" })) {\n setPromotionMove(moveData);\n return false; // Prevent the move until promotion is selected\n }\n\n return makeMove(moveData);\n },\n onSquareClick: ({ square }) => {\n if (square.match(/^[a-h][1-8]$/)) {\n onSquareClick(square as Square);\n }\n },\n onSquareRightClick: onSquareRightClick,\n allowDrawingArrows: true,\n animationDurationInMs: game.history().length === 0 ? 0 : 300,\n };\n\n const mergedOptions = deepMergeChessboardOptions(baseOptions, options);\n\n const mergedStyle = {\n ...userStyle,\n position: \"relative\" as const,\n };\n\n return (\n <div ref={ref} className={className} style={mergedStyle} {...rest}>\n <Chessboard options={mergedOptions} />\n {promotionMove && (\n <>\n {/* Backdrop overlay - click to cancel */}\n <div\n onClick={() => setPromotionMove(null)}\n onContextMenu={(e) => {\n e.preventDefault();\n setPromotionMove(null);\n }}\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n backgroundColor: \"rgba(0, 0, 0, 0.1)\",\n zIndex: 1000,\n }}\n />\n {/* Promotion piece selection */}\n <div\n style={{\n position: \"absolute\",\n top: promotionMove.to?.[1]?.includes(\"8\") ? 0 : \"auto\",\n bottom: promotionMove.to?.[1].includes(\"1\") ? 0 : \"auto\",\n left: promotionSquareLeft,\n backgroundColor: \"white\",\n width: squareWidth,\n zIndex: 1001,\n display: \"flex\",\n flexDirection: \"column\",\n boxShadow: \"0 0 10px 0 rgba(0, 0, 0, 0.5)\",\n }}\n >\n {[\"q\", \"r\", \"n\", \"b\"].map((piece) => (\n <button\n key={piece}\n onClick={() => onPromotionPieceSelect(piece)}\n onContextMenu={(e) => {\n e.preventDefault();\n }}\n style={{\n width: \"100%\",\n aspectRatio: \"1\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n padding: 0,\n border: \"none\",\n cursor: \"pointer\",\n backgroundColor: \"white\",\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.backgroundColor = \"#f0f0f0\";\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = \"white\";\n }}\n >\n {defaultPieces[\n `${turn}${piece.toUpperCase()}` as keyof typeof defaultPieces\n ]()}\n </button>\n ))}\n </div>\n </>\n )}\n </div>\n );\n },\n);\n\nBoard.displayName = \"ChessGame.Board\";\n","import { type Chess, type Square } from \"chess.js\";\nimport { type CSSProperties } from \"react\";\nimport { merge } from \"lodash\";\nimport type { ChessboardOptions } from \"react-chessboard\";\nimport { getDestinationSquares, type GameInfo } from \"./chess\";\nimport type { ChessGameTheme } from \"../theme/types\";\nimport { defaultGameTheme } from \"../theme/defaults\";\n\n/**\n * Generates custom square styles based on game state and theme.\n *\n * @param game - Chess.js game instance\n * @param info - Game info containing lastMove, isCheck, turn\n * @param activeSquare - Currently selected square (if any)\n * @param theme - Theme configuration (defaults to defaultGameTheme)\n * @returns Record of square names to CSS properties\n */\nexport const getCustomSquareStyles = (\n game: Chess,\n info: GameInfo,\n activeSquare: Square | null,\n theme: ChessGameTheme = defaultGameTheme,\n) => {\n const customSquareStyles: Record<string, CSSProperties> = {};\n\n const { lastMove, isCheck, turn } = info;\n\n if (lastMove) {\n customSquareStyles[lastMove.from] = {\n backgroundColor: theme.state.lastMove,\n };\n customSquareStyles[lastMove.to] = {\n backgroundColor: theme.state.lastMove,\n };\n }\n\n if (activeSquare) {\n customSquareStyles[activeSquare] = {\n backgroundColor: theme.state.activeSquare,\n };\n }\n\n if (activeSquare) {\n const destinationSquares = getDestinationSquares(game, activeSquare);\n destinationSquares.forEach((square) => {\n customSquareStyles[square] = {\n background:\n game.get(square) && game.get(square)?.color !== turn\n ? `radial-gradient(circle, ${theme.indicators.capture} 85%, transparent 85%)`\n : `radial-gradient(circle, ${theme.indicators.move} 25%, transparent 25%)`,\n };\n });\n }\n\n if (isCheck) {\n game.board().forEach((row) => {\n return row.forEach((square) => {\n if (square?.type === \"k\" && square?.color === info.turn) {\n customSquareStyles[square.square] = {\n backgroundColor: theme.state.check,\n };\n }\n });\n });\n }\n return customSquareStyles;\n};\n\n/**\n * Smart deep merge for ChessboardOptions that handles different property types appropriately:\n * - Functions: Overwrite (custom functions replace base functions)\n * - Objects: Deep merge (nested objects merge recursively)\n * - Primitives: Overwrite (custom values replace base values)\n *\n * This ensures that computed options (like squareStyles with move highlighting) are preserved\n * while allowing custom options to extend or override them intelligently.\n *\n * @param baseOptions - The computed base options (e.g., computed squareStyles, event handlers)\n * @param customOptions - Custom options provided by the user\n * @returns Intelligently merged ChessboardOptions\n */\nexport const deepMergeChessboardOptions = (\n baseOptions: ChessboardOptions,\n customOptions?: Partial<ChessboardOptions>,\n): ChessboardOptions => {\n if (!customOptions) {\n return { ...baseOptions }; // Return a new object even when no custom options\n }\n\n const result = merge({}, baseOptions, customOptions, {\n customizer: (_objValue: unknown, srcValue: unknown) => {\n // Functions should always overwrite (not merge)\n // This is important for event handlers like onSquareClick, onPieceDrop, etc.\n if (typeof srcValue === \"function\") {\n return srcValue;\n }\n\n // For arrays, we typically want to overwrite rather than merge\n // This avoids unexpected behavior with array concatenation\n if (Array.isArray(srcValue)) {\n return srcValue;\n }\n\n // Let lodash handle objects with default deep merge behavior\n // This will properly merge nested objects like squareStyles, dropSquareStyle, etc.\n return undefined; // Use default merge behavior\n },\n });\n\n // Clean up any unwanted properties that lodash might add\n delete (result as Record<string, unknown>).customizer;\n\n return result;\n};\n","import { useMemo } from \"react\";\nimport { defaultSounds, type Sound } from \"../../../assets/sounds\";\nimport { useBoardSounds } from \"../../../hooks/useBoardSounds\";\n\n/**\n * Props for the Sounds component\n *\n * Note: This is a logic-only component that returns null and does not render\n * any DOM elements. It sets up board sounds via the useBoardSounds hook.\n * Therefore, it does not accept HTML attributes like className, style, etc.\n */\nexport type SoundsProps = {\n sounds?: Partial<Record<Sound, string>>;\n};\n\nexport const Sounds: React.FC<SoundsProps> = ({ sounds }) => {\n const customSoundsAudios = useMemo(() => {\n if (typeof window === \"undefined\" || typeof Audio === \"undefined\") {\n return {} as Record<Sound, HTMLAudioElement>;\n }\n\n return Object.entries({ ...defaultSounds, sounds }).reduce(\n (acc, [name, base64]) => {\n acc[name as Sound] = new Audio(`data:audio/wav;base64,${base64}`);\n return acc;\n },\n {} as Record<Sound, HTMLAudioElement>,\n );\n }, [sounds]);\n useBoardSounds(customSoundsAudios);\n return null;\n};\n\nSounds.displayName = \"ChessGame.Sounds\";\n","export type Sound = \"check\" | \"move\" | \"capture\" | \"gameOver\";\nexport type Sounds = Record<Sound, HTMLAudioElement>;\n\nconst SILENCE = \"Li4vU2lsZW5jZS5vZ2c=\";\n\nexport const defaultSounds: Record<Sound, string> = {\n move: \"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\",\n capture:\n \"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\",\n check: SILENCE,\n gameOver:\n \"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\",\n};\n","import { useEffect } from \"react\";\nimport { useChessGameContext } from \"./useChessGameContext\";\nimport { type Sound } from \"../assets/sounds\";\n\nconst playSound = async (audioElement: HTMLAudioElement) => {\n try {\n await audioElement.play();\n } catch (error) {\n console.warn(\"Failed to play sound:\", (error as Error).message);\n }\n};\n\nexport const useBoardSounds = (sounds: Record<Sound, HTMLAudioElement>) => {\n const {\n info: { lastMove, isCheckmate },\n } = useChessGameContext();\n\n useEffect(() => {\n if (Object.keys(sounds).length === 0) {\n return;\n }\n\n if (isCheckmate && sounds.gameOver) {\n playSound(sounds.gameOver);\n return;\n }\n\n if (lastMove?.captured && sounds.capture) {\n playSound(sounds.capture);\n return;\n }\n\n if (lastMove && sounds.move) {\n playSound(sounds.move);\n }\n }, [lastMove]);\n};\n","import { useEffect } from \"react\";\nimport {\n defaultKeyboardControls,\n KeyboardControls,\n} from \"../components/ChessGame/parts/KeyboardControls\";\nimport { useChessGameContext } from \"./useChessGameContext\";\n\nexport const useKeyboardControls = (controls?: KeyboardControls) => {\n const gameContext = useChessGameContext();\n if (!gameContext) {\n throw new Error(\"ChessGameContext not found\");\n }\n const keyboardControls = { ...defaultKeyboardControls, ...controls };\n useEffect(() => {\n const handleKeyDown = (event: KeyboardEvent) => {\n const handler = keyboardControls[event.key];\n if (handler) {\n event.preventDefault();\n handler(gameContext);\n }\n };\n window.addEventListener(\"keydown\", handleKeyDown);\n return () => {\n window.removeEventListener(\"keydown\", handleKeyDown);\n };\n }, [gameContext]);\n return null;\n};\n","import {\n ChessGameContextType,\n useChessGameContext,\n} from \"../../../hooks/useChessGameContext\";\nimport { useKeyboardControls } from \"../../../hooks/useKeyboardControls\";\n\nexport type KeyboardControls = Record<\n string,\n (context: ChessGameContextType) => void\n>;\n\nexport const defaultKeyboardControls: KeyboardControls = {\n ArrowLeft: (context) => context.methods.goToPreviousMove(),\n ArrowRight: (context) => context.methods.goToNextMove(),\n ArrowUp: (context) => context.methods.goToStart(),\n ArrowDown: (context) => context.methods.goToEnd(),\n};\n\n/**\n * Props for the KeyboardControls component\n *\n * Note: This is a logic-only component that returns null and does not render\n * any DOM elements. It sets up keyboard controls via the useKeyboardControls hook.\n * Therefore, it does not accept HTML attributes like className, style, etc.\n */\ntype KeyboardControlsProps = {\n controls?: KeyboardControls;\n};\n\nexport const KeyboardControls: React.FC<KeyboardControlsProps> = ({\n controls,\n}) => {\n const gameContext = useChessGameContext();\n if (!gameContext) {\n throw new Error(\"ChessGameContext not found\");\n }\n const keyboardControls = { ...defaultKeyboardControls, ...controls };\n useKeyboardControls(keyboardControls);\n return null;\n};\n\nKeyboardControls.displayName = \"ChessGame.KeyboardControls\";\n","import React from \"react\";\nimport { useChessGameContext } from \"../../../hooks/useChessGameContext\";\nimport {\n Display as ClockDisplay,\n Switch as ClockSwitch,\n PlayPause as ClockPlayPause,\n Reset as ClockReset,\n ChessClockContext,\n} from \"@react-chess-tools/react-chess-clock\";\nimport type {\n ChessClockDisplayProps,\n ChessClockControlProps,\n ChessClockPlayPauseProps,\n ChessClockResetProps,\n ClockColor,\n} from \"@react-chess-tools/react-chess-clock\";\n\nexport type {\n ChessClockDisplayProps,\n ChessClockControlProps,\n ChessClockPlayPauseProps,\n ChessClockResetProps,\n ClockColor,\n} from \"@react-chess-tools/react-chess-clock\";\n\nexport interface ClockDisplayProps extends Omit<\n ChessClockDisplayProps,\n \"color\"\n> {\n color: ClockColor;\n}\n\n/**\n * ChessGame.Clock.Display - Autonomous display component\n *\n * Wraps react-chess-clock's Display component, providing clock state from ChessGame.Root context.\n * No need to pass timeControl - it's inherited from the root.\n *\n * @example\n * ```tsx\n * <ChessGame.Root timeControl={{ time: \"5+3\" }}>\n * <ChessGame.Clock.Display color=\"white\" />\n * <ChessGame.Board />\n * <ChessGame.Clock.Display color=\"black\" />\n * </ChessGame.Root>\n * ```\n */\nexport const Display = React.forwardRef<HTMLDivElement, ClockDisplayProps>(\n ({ color, ...rest }, ref) => {\n const { clock } = useChessGameContext();\n\n if (!clock) {\n return null;\n }\n\n return (\n <ChessClockContext.Provider value={clock}>\n <ClockDisplay ref={ref} color={color} {...rest} />\n </ChessClockContext.Provider>\n );\n },\n);\n\nDisplay.displayName = \"ChessGame.Clock.Display\";\n\n/**\n * ChessGame.Clock.Switch - Manual switch control\n *\n * Wraps react-chess-clock's Switch component, providing clock state from ChessGame.Root context.\n *\n * @example\n * ```tsx\n * <ChessGame.Root timeControl={{ time: \"5+3\" }}>\n * <ChessGame.Clock.Switch>Switch Clock</ChessGame.Clock.Switch>\n * </ChessGame.Root>\n * ```\n */\nexport const Switch = React.forwardRef<\n HTMLElement,\n React.PropsWithChildren<ChessClockControlProps>\n>(({ children, ...rest }, ref) => {\n const { clock } = useChessGameContext();\n\n if (!clock) {\n return null;\n }\n\n return (\n <ChessClockContext.Provider value={clock}>\n <ClockSwitch ref={ref} {...rest}>\n {children}\n </ClockSwitch>\n </ChessClockContext.Provider>\n );\n});\n\nSwitch.displayName = \"ChessGame.Clock.Switch\";\n\n/**\n * ChessGame.Clock.PlayPause - Play/pause control\n *\n * Wraps react-chess-clock's PlayPause component, providing clock state from ChessGame.Root context.\n *\n * @example\n * ```tsx\n * <ChessGame.Root timeControl={{ time: \"5+3\" }}>\n * <ChessGame.Clock.PlayPause\n * startContent=\"Start\"\n * pauseContent=\"Pause\"\n * resumeContent=\"Resume\"\n * />\n * </ChessGame.Root>\n * ```\n */\nexport const PlayPause = React.forwardRef<\n HTMLElement,\n React.PropsWithChildren<ChessClockPlayPauseProps>\n>(({ children, ...rest }, ref) => {\n const { clock } = useChessGameContext();\n\n if (!clock) {\n return null;\n }\n\n return (\n <ChessClockContext.Provider value={clock}>\n <ClockPlayPause ref={ref} {...rest}>\n {children}\n </ClockPlayPause>\n </ChessClockContext.Provider>\n );\n});\n\nPlayPause.displayName = \"ChessGame.Clock.PlayPause\";\n\n/**\n * ChessGame.Clock.Reset - Reset control\n *\n * Wraps react-chess-clock's Reset component, providing clock state from ChessGame.Root context.\n *\n * @example\n * ```tsx\n * <ChessGame.Root timeControl={{ time: \"5+3\" }}>\n * <ChessGame.Clock.Reset>Reset</ChessGame.Clock.Reset>\n * </ChessGame.Root>\n * ```\n */\nexport const Reset = React.forwardRef<\n HTMLElement,\n React.PropsWithChildren<ChessClockResetProps>\n>(({ children, ...rest }, ref) => {\n const { clock } = useChessGameContext();\n\n if (!clock) {\n return null;\n }\n\n return (\n <ChessClockContext.Provider value={clock}>\n <ClockReset ref={ref} {...rest}>\n {children}\n </ClockReset>\n </ChessClockContext.Provider>\n );\n});\n\nReset.displayName = \"ChessGame.Clock.Reset\";\n\nexport const Clock = {\n Display,\n Switch,\n PlayPause,\n Reset,\n};\n","import { Root } from \"./parts/Root\";\nimport { Board } from \"./parts/Board\";\nimport { Sounds } from \"./parts/Sounds\";\nimport { KeyboardControls } from \"./parts/KeyboardControls\";\nimport { Clock } from \"./Clock\";\n\nexport const ChessGame = {\n Root,\n Board,\n Sounds,\n KeyboardControls,\n Clock,\n};\n","// Components\nexport { ChessGame } from \"./components/ChessGame\";\n\n// Clock - Re-export from react-chess-clock for convenience\nexport { ChessClock } from \"@react-chess-tools/react-chess-clock\";\nexport type {\n TimeControlConfig,\n TimeControlInput,\n TimingMethod,\n ClockStartMode,\n UseChessClockReturn,\n} from \"@react-chess-tools/react-chess-clock\";\n\n// Hooks & Context\nexport { useChessGameContext } from \"./hooks/useChessGameContext\";\nexport { useChessGame } from \"./hooks/useChessGame\";\nexport type { ChessGameContextType } from \"./hooks/useChessGameContext\";\nexport type { useChessGameProps } from \"./hooks/useChessGame\";\n\n// Audio Types\nexport type { Sound, Sounds } from \"./assets/sounds\";\nexport type { SoundsProps } from \"./components/ChessGame/parts/Sounds\";\n\n// Keyboard Types\nexport type { KeyboardControls } from \"./components/ChessGame/parts/KeyboardControls\";\n\n// Utility Types\nexport type { GameInfo } from \"./utils/chess\";\nexport { deepMergeChessboardOptions } from \"./utils/board\";\n\n// Component Props\nexport type { ChessGameProps } from \"./components/ChessGame/parts/Board\";\nexport type { RootProps } from \"./components/ChessGame/parts/Root\";\n\n// Theme - Types\nexport type {\n ChessGameTheme,\n BoardTheme,\n StateTheme,\n IndicatorTheme,\n PartialChessGameTheme,\n DeepPartial,\n} from \"./theme/types\";\n\n// Theme - Values\nexport { defaultGameTheme } from \"./theme/defaults\";\nexport { lichessTheme, chessComTheme } from \"./theme/presets\";\nexport { themes } from \"./theme\";\n\n// Theme - Utilities\nexport { mergeTheme, mergeThemeWith } from \"./theme/utils\";\nexport { useChessGameTheme, ChessGameThemeContext } from \"./theme/context\";\n","import type { ChessGameTheme } from \"./types\";\n\n/**\n * Lichess-inspired theme with green highlights\n */\nexport const lichessTheme: ChessGameTheme = {\n board: {\n lightSquare: { backgroundColor: \"#f0d9b5\" },\n darkSquare: { backgroundColor: \"#b58863\" },\n },\n state: {\n lastMove: \"rgba(155, 199, 0, 0.41)\",\n check: \"rgba(255, 0, 0, 0.5)\",\n activeSquare: \"rgba(20, 85, 30, 0.5)\",\n dropSquare: { backgroundColor: \"rgba(20, 85, 30, 0.3)\" },\n },\n indicators: {\n move: \"rgba(20, 85, 30, 0.3)\",\n capture: \"rgba(20, 85, 30, 0.3)\",\n },\n};\n\n/**\n * Chess.com-inspired theme with green board and yellow highlights\n */\nexport const chessComTheme: ChessGameTheme = {\n board: {\n lightSquare: { backgroundColor: \"#ebecd0\" },\n darkSquare: { backgroundColor: \"#779556\" },\n },\n state: {\n lastMove: \"rgba(255, 255, 0, 0.5)\",\n check: \"rgba(255, 0, 0, 0.7)\",\n activeSquare: \"rgba(255, 255, 0, 0.5)\",\n dropSquare: { backgroundColor: \"rgba(255, 255, 0, 0.4)\" },\n },\n indicators: {\n move: \"rgba(0, 0, 0, 0.1)\",\n capture: \"rgba(0, 0, 0, 0.1)\",\n },\n};\n","// Types\nexport type {\n ChessGameTheme,\n BoardTheme,\n StateTheme,\n IndicatorTheme,\n PartialChessGameTheme,\n DeepPartial,\n} from \"./types\";\n\n// Default theme\nexport { defaultGameTheme } from \"./defaults\";\n\n// Preset themes\nexport { lichessTheme, chessComTheme } from \"./presets\";\n\n// All themes as a single object\nimport { defaultGameTheme } from \"./defaults\";\nimport { lichessTheme, chessComTheme } from \"./presets\";\n\nexport const themes = {\n default: defaultGameTheme,\n lichess: lichessTheme,\n chessCom: chessComTheme,\n} as const;\n\n// Utilities\nexport { mergeTheme, mergeThemeWith } from \"./utils\";\n\n// Context and hook\nexport {\n ChessGameThemeContext,\n useChessGameTheme,\n ThemeProvider,\n} from \"./context\";\nexport type { ThemeProviderProps } from \"./context\";\n"],"mappings":"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","names":["React","Chess","Chess","fen","orientation","React","React","React","React","React","merge","merge","React","_a","useEffect","useEffect","useEffect","useEffect","KeyboardControls","React","React","KeyboardControls"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@react-chess-tools/react-chess-game",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "react-chess-game is a React component bridging chess.js with react-chessboard to offer a full-featured, ready-to-integrate chess board experience.",
5
5
  "type": "module",
6
6
  "exports": {
@@ -40,6 +40,7 @@
40
40
  "license": "MIT",
41
41
  "dependencies": {
42
42
  "@radix-ui/react-slot": "^1.2.4",
43
+ "@react-chess-tools/react-chess-clock": "^1.0.1",
43
44
  "chess.js": "^1.4.0",
44
45
  "lodash": "^4.17.21",
45
46
  "react-chessboard": "^5.8.6"