@react-chess-tools/react-chess-game 0.5.2 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -0
- package/dist/index.cjs +775 -0
- package/dist/index.cjs.map +1 -0
- package/dist/{index.d.mts → index.d.cts} +118 -12
- package/dist/index.d.ts +264 -0
- package/dist/{index.mjs → index.js} +171 -38
- package/dist/index.js.map +1 -0
- package/package.json +18 -9
- package/src/components/ChessGame/Theme.stories.tsx +242 -0
- package/src/components/ChessGame/ThemePresets.stories.tsx +144 -0
- package/src/components/ChessGame/parts/Board.tsx +6 -4
- package/src/components/ChessGame/parts/Root.tsx +11 -1
- package/src/docs/Theming.mdx +281 -0
- package/src/hooks/useChessGame.ts +23 -7
- package/src/index.ts +19 -0
- package/src/theme/__tests__/context.test.tsx +75 -0
- package/src/theme/__tests__/defaults.test.ts +61 -0
- package/src/theme/__tests__/utils.test.ts +106 -0
- package/src/theme/context.tsx +37 -0
- package/src/theme/defaults.ts +22 -0
- package/src/theme/index.ts +36 -0
- package/src/theme/presets.ts +41 -0
- package/src/theme/types.ts +56 -0
- package/src/theme/utils.ts +47 -0
- package/src/utils/__tests__/board.test.ts +118 -0
- package/src/utils/board.ts +18 -9
- package/src/utils/chess.ts +25 -5
- package/coverage/clover.xml +0 -6
- package/coverage/coverage-final.json +0 -1
- package/coverage/lcov-report/base.css +0 -224
- package/coverage/lcov-report/block-navigation.js +0 -87
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +0 -101
- package/coverage/lcov-report/prettify.css +0 -1
- package/coverage/lcov-report/prettify.js +0 -2
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +0 -196
- package/coverage/lcov.info +0 -0
- package/dist/index.mjs.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../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":["// Components\nexport { ChessGame } from \"./components/ChessGame\";\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 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","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 {\n options?: ChessboardOptions;\n}\n\nexport const Board: React.FC<ChessGameProps> = ({ options = {} }) => {\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 return (\n <div style={{ position: \"relative\" }}>\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","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\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","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\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","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":["import_react","import_chess","_","React","fen","orientation","import_react","React","import_react","React","import_lodash","React","import_react","import_lodash","React","_a","import_react","import_react","import_react","KeyboardControls","KeyboardControls"]}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ChessboardOptions } from 'react-chessboard';
|
|
2
|
-
import * as
|
|
2
|
+
import * as React$1 from 'react';
|
|
3
|
+
import React__default, { CSSProperties } from 'react';
|
|
3
4
|
import * as chess_js from 'chess.js';
|
|
4
5
|
import { Color, Chess } from 'chess.js';
|
|
5
6
|
|
|
@@ -14,9 +15,61 @@ interface ChessGameProps {
|
|
|
14
15
|
options?: ChessboardOptions;
|
|
15
16
|
}
|
|
16
17
|
|
|
18
|
+
/**
|
|
19
|
+
* Board appearance configuration - colors for light and dark squares
|
|
20
|
+
*/
|
|
21
|
+
interface BoardTheme {
|
|
22
|
+
/** Style for light squares */
|
|
23
|
+
lightSquare: CSSProperties;
|
|
24
|
+
/** Style for dark squares */
|
|
25
|
+
darkSquare: CSSProperties;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Game state highlight colors (RGBA color strings)
|
|
29
|
+
*/
|
|
30
|
+
interface StateTheme {
|
|
31
|
+
/** Background color for last move from/to squares */
|
|
32
|
+
lastMove: string;
|
|
33
|
+
/** Background color for king when in check */
|
|
34
|
+
check: string;
|
|
35
|
+
/** Background color for currently selected piece's square */
|
|
36
|
+
activeSquare: string;
|
|
37
|
+
/** Full CSSProperties for valid drop target squares */
|
|
38
|
+
dropSquare: CSSProperties;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Move indicator styling - colors for move dots and capture rings
|
|
42
|
+
*/
|
|
43
|
+
interface IndicatorTheme {
|
|
44
|
+
/** Color for move dots on empty destination squares (used in radial-gradient) */
|
|
45
|
+
move: string;
|
|
46
|
+
/** Color for capture rings on capturable pieces (used in radial-gradient) */
|
|
47
|
+
capture: string;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Complete theme configuration for ChessGame component
|
|
51
|
+
*/
|
|
52
|
+
interface ChessGameTheme {
|
|
53
|
+
board: BoardTheme;
|
|
54
|
+
state: StateTheme;
|
|
55
|
+
indicators: IndicatorTheme;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Utility type for creating partial versions of nested objects
|
|
59
|
+
*/
|
|
60
|
+
type DeepPartial<T> = {
|
|
61
|
+
[P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* Partial theme for user customization - allows overriding only specific properties
|
|
65
|
+
*/
|
|
66
|
+
type PartialChessGameTheme = DeepPartial<ChessGameTheme>;
|
|
67
|
+
|
|
17
68
|
interface RootProps {
|
|
18
69
|
fen?: string;
|
|
19
70
|
orientation?: Color;
|
|
71
|
+
/** Optional theme configuration. Supports partial themes - only override the colors you need. */
|
|
72
|
+
theme?: PartialChessGameTheme;
|
|
20
73
|
}
|
|
21
74
|
|
|
22
75
|
type useChessGameProps = {
|
|
@@ -84,11 +137,7 @@ declare const useChessGameContext: () => {
|
|
|
84
137
|
hasPlayerLost: boolean;
|
|
85
138
|
};
|
|
86
139
|
methods: {
|
|
87
|
-
makeMove: (move:
|
|
88
|
-
from: string;
|
|
89
|
-
to: string;
|
|
90
|
-
promotion?: string | undefined;
|
|
91
|
-
} | null) => boolean;
|
|
140
|
+
makeMove: (move: Parameters<chess_js.Chess["move"]>[0]) => boolean;
|
|
92
141
|
setPosition: (fen: string, orientation: chess_js.Color) => void;
|
|
93
142
|
flipBoard: () => void;
|
|
94
143
|
goToMove: (moveIndex: number) => void;
|
|
@@ -107,11 +156,11 @@ type KeyboardControls = Record<string, (context: ChessGameContextType) => void>;
|
|
|
107
156
|
declare const KeyboardControls: React.FC<KeyboardControlsProps>;
|
|
108
157
|
|
|
109
158
|
declare const ChessGame: {
|
|
110
|
-
Root:
|
|
111
|
-
Board:
|
|
112
|
-
Sounds:
|
|
113
|
-
KeyboardControls:
|
|
114
|
-
controls?: KeyboardControls
|
|
159
|
+
Root: React$1.FC<React$1.PropsWithChildren<RootProps>>;
|
|
160
|
+
Board: React$1.FC<ChessGameProps>;
|
|
161
|
+
Sounds: React$1.FC<SoundsProps>;
|
|
162
|
+
KeyboardControls: React$1.FC<{
|
|
163
|
+
controls?: KeyboardControls;
|
|
115
164
|
}>;
|
|
116
165
|
};
|
|
117
166
|
|
|
@@ -155,4 +204,61 @@ type GameInfo = ReturnType<typeof getGameInfo>;
|
|
|
155
204
|
*/
|
|
156
205
|
declare const deepMergeChessboardOptions: (baseOptions: ChessboardOptions, customOptions?: Partial<ChessboardOptions>) => ChessboardOptions;
|
|
157
206
|
|
|
158
|
-
|
|
207
|
+
/**
|
|
208
|
+
* Default theme for ChessGame component.
|
|
209
|
+
* These values match the original hardcoded colors for backward compatibility.
|
|
210
|
+
*/
|
|
211
|
+
declare const defaultGameTheme: ChessGameTheme;
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Lichess-inspired theme with green highlights
|
|
215
|
+
*/
|
|
216
|
+
declare const lichessTheme: ChessGameTheme;
|
|
217
|
+
/**
|
|
218
|
+
* Chess.com-inspired theme with green board and yellow highlights
|
|
219
|
+
*/
|
|
220
|
+
declare const chessComTheme: ChessGameTheme;
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Deep merges a partial theme with the default theme.
|
|
224
|
+
* Allows users to override only specific theme properties while keeping defaults for the rest.
|
|
225
|
+
*
|
|
226
|
+
* @param partialTheme - Partial theme with only the properties to override
|
|
227
|
+
* @returns Complete theme with overridden properties merged with defaults
|
|
228
|
+
*
|
|
229
|
+
* @example
|
|
230
|
+
* ```typescript
|
|
231
|
+
* const customTheme = mergeTheme({
|
|
232
|
+
* state: { lastMove: "rgba(100, 200, 100, 0.6)" }
|
|
233
|
+
* });
|
|
234
|
+
* // Returns full theme with only lastMove color changed
|
|
235
|
+
* ```
|
|
236
|
+
*/
|
|
237
|
+
declare const mergeTheme: (partialTheme?: PartialChessGameTheme) => ChessGameTheme;
|
|
238
|
+
/**
|
|
239
|
+
* Deep merges a partial theme with a base theme.
|
|
240
|
+
* Useful when extending an existing theme.
|
|
241
|
+
*
|
|
242
|
+
* @param baseTheme - The base theme to extend
|
|
243
|
+
* @param partialTheme - Partial theme with properties to override
|
|
244
|
+
* @returns Complete theme with overridden properties
|
|
245
|
+
*/
|
|
246
|
+
declare const mergeThemeWith: (baseTheme: ChessGameTheme, partialTheme?: PartialChessGameTheme) => ChessGameTheme;
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Context for ChessGame theme
|
|
250
|
+
*/
|
|
251
|
+
declare const ChessGameThemeContext: React__default.Context<ChessGameTheme>;
|
|
252
|
+
/**
|
|
253
|
+
* Hook to access the current ChessGame theme.
|
|
254
|
+
* Returns the default theme if no ThemeProvider is present.
|
|
255
|
+
*/
|
|
256
|
+
declare const useChessGameTheme: () => ChessGameTheme;
|
|
257
|
+
|
|
258
|
+
declare const themes: {
|
|
259
|
+
readonly default: ChessGameTheme;
|
|
260
|
+
readonly lichess: ChessGameTheme;
|
|
261
|
+
readonly chessCom: ChessGameTheme;
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
export { type BoardTheme, ChessGame, type ChessGameContextType, type ChessGameProps, type ChessGameTheme, ChessGameThemeContext, type DeepPartial, type GameInfo, type IndicatorTheme, KeyboardControls, type PartialChessGameTheme, type RootProps, type Sound, type Sounds, type SoundsProps, type StateTheme, chessComTheme, deepMergeChessboardOptions, defaultGameTheme, lichessTheme, mergeTheme, mergeThemeWith, themes, useChessGame, useChessGameContext, type useChessGameProps, useChessGameTheme };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
import { ChessboardOptions } from 'react-chessboard';
|
|
2
|
+
import * as React$1 from 'react';
|
|
3
|
+
import React__default, { CSSProperties } from 'react';
|
|
4
|
+
import * as chess_js from 'chess.js';
|
|
5
|
+
import { Color, Chess } from 'chess.js';
|
|
6
|
+
|
|
7
|
+
type Sound = "check" | "move" | "capture" | "gameOver";
|
|
8
|
+
type Sounds = Record<Sound, HTMLAudioElement>;
|
|
9
|
+
|
|
10
|
+
type SoundsProps = {
|
|
11
|
+
sounds?: Partial<Record<Sound, string>>;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
interface ChessGameProps {
|
|
15
|
+
options?: ChessboardOptions;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Board appearance configuration - colors for light and dark squares
|
|
20
|
+
*/
|
|
21
|
+
interface BoardTheme {
|
|
22
|
+
/** Style for light squares */
|
|
23
|
+
lightSquare: CSSProperties;
|
|
24
|
+
/** Style for dark squares */
|
|
25
|
+
darkSquare: CSSProperties;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Game state highlight colors (RGBA color strings)
|
|
29
|
+
*/
|
|
30
|
+
interface StateTheme {
|
|
31
|
+
/** Background color for last move from/to squares */
|
|
32
|
+
lastMove: string;
|
|
33
|
+
/** Background color for king when in check */
|
|
34
|
+
check: string;
|
|
35
|
+
/** Background color for currently selected piece's square */
|
|
36
|
+
activeSquare: string;
|
|
37
|
+
/** Full CSSProperties for valid drop target squares */
|
|
38
|
+
dropSquare: CSSProperties;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Move indicator styling - colors for move dots and capture rings
|
|
42
|
+
*/
|
|
43
|
+
interface IndicatorTheme {
|
|
44
|
+
/** Color for move dots on empty destination squares (used in radial-gradient) */
|
|
45
|
+
move: string;
|
|
46
|
+
/** Color for capture rings on capturable pieces (used in radial-gradient) */
|
|
47
|
+
capture: string;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Complete theme configuration for ChessGame component
|
|
51
|
+
*/
|
|
52
|
+
interface ChessGameTheme {
|
|
53
|
+
board: BoardTheme;
|
|
54
|
+
state: StateTheme;
|
|
55
|
+
indicators: IndicatorTheme;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Utility type for creating partial versions of nested objects
|
|
59
|
+
*/
|
|
60
|
+
type DeepPartial<T> = {
|
|
61
|
+
[P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* Partial theme for user customization - allows overriding only specific properties
|
|
65
|
+
*/
|
|
66
|
+
type PartialChessGameTheme = DeepPartial<ChessGameTheme>;
|
|
67
|
+
|
|
68
|
+
interface RootProps {
|
|
69
|
+
fen?: string;
|
|
70
|
+
orientation?: Color;
|
|
71
|
+
/** Optional theme configuration. Supports partial themes - only override the colors you need. */
|
|
72
|
+
theme?: PartialChessGameTheme;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
type useChessGameProps = {
|
|
76
|
+
fen?: string;
|
|
77
|
+
orientation?: Color;
|
|
78
|
+
};
|
|
79
|
+
declare const useChessGame: ({ fen, orientation: initialOrientation, }?: useChessGameProps) => {
|
|
80
|
+
game: Chess;
|
|
81
|
+
currentFen: string;
|
|
82
|
+
currentPosition: string;
|
|
83
|
+
orientation: Color;
|
|
84
|
+
currentMoveIndex: number;
|
|
85
|
+
isLatestMove: boolean;
|
|
86
|
+
info: {
|
|
87
|
+
turn: Color;
|
|
88
|
+
isPlayerTurn: boolean;
|
|
89
|
+
isOpponentTurn: boolean;
|
|
90
|
+
moveNumber: number;
|
|
91
|
+
lastMove: chess_js.Move | undefined;
|
|
92
|
+
isCheck: boolean;
|
|
93
|
+
isCheckmate: boolean;
|
|
94
|
+
isDraw: boolean;
|
|
95
|
+
isStalemate: boolean;
|
|
96
|
+
isThreefoldRepetition: boolean;
|
|
97
|
+
isInsufficientMaterial: boolean;
|
|
98
|
+
isGameOver: boolean;
|
|
99
|
+
isDrawn: boolean;
|
|
100
|
+
hasPlayerWon: boolean;
|
|
101
|
+
hasPlayerLost: boolean;
|
|
102
|
+
};
|
|
103
|
+
methods: {
|
|
104
|
+
makeMove: (move: Parameters<Chess["move"]>[0]) => boolean;
|
|
105
|
+
setPosition: (fen: string, orientation: Color) => void;
|
|
106
|
+
flipBoard: () => void;
|
|
107
|
+
goToMove: (moveIndex: number) => void;
|
|
108
|
+
goToStart: () => void;
|
|
109
|
+
goToEnd: () => void;
|
|
110
|
+
goToPreviousMove: () => void;
|
|
111
|
+
goToNextMove: () => void;
|
|
112
|
+
};
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
declare const useChessGameContext: () => {
|
|
116
|
+
game: chess_js.Chess;
|
|
117
|
+
currentFen: string;
|
|
118
|
+
currentPosition: string;
|
|
119
|
+
orientation: chess_js.Color;
|
|
120
|
+
currentMoveIndex: number;
|
|
121
|
+
isLatestMove: boolean;
|
|
122
|
+
info: {
|
|
123
|
+
turn: chess_js.Color;
|
|
124
|
+
isPlayerTurn: boolean;
|
|
125
|
+
isOpponentTurn: boolean;
|
|
126
|
+
moveNumber: number;
|
|
127
|
+
lastMove: chess_js.Move | undefined;
|
|
128
|
+
isCheck: boolean;
|
|
129
|
+
isCheckmate: boolean;
|
|
130
|
+
isDraw: boolean;
|
|
131
|
+
isStalemate: boolean;
|
|
132
|
+
isThreefoldRepetition: boolean;
|
|
133
|
+
isInsufficientMaterial: boolean;
|
|
134
|
+
isGameOver: boolean;
|
|
135
|
+
isDrawn: boolean;
|
|
136
|
+
hasPlayerWon: boolean;
|
|
137
|
+
hasPlayerLost: boolean;
|
|
138
|
+
};
|
|
139
|
+
methods: {
|
|
140
|
+
makeMove: (move: Parameters<chess_js.Chess["move"]>[0]) => boolean;
|
|
141
|
+
setPosition: (fen: string, orientation: chess_js.Color) => void;
|
|
142
|
+
flipBoard: () => void;
|
|
143
|
+
goToMove: (moveIndex: number) => void;
|
|
144
|
+
goToStart: () => void;
|
|
145
|
+
goToEnd: () => void;
|
|
146
|
+
goToPreviousMove: () => void;
|
|
147
|
+
goToNextMove: () => void;
|
|
148
|
+
};
|
|
149
|
+
};
|
|
150
|
+
type ChessGameContextType = ReturnType<typeof useChessGame>;
|
|
151
|
+
|
|
152
|
+
type KeyboardControlsProps = {
|
|
153
|
+
controls?: KeyboardControls;
|
|
154
|
+
};
|
|
155
|
+
type KeyboardControls = Record<string, (context: ChessGameContextType) => void>;
|
|
156
|
+
declare const KeyboardControls: React.FC<KeyboardControlsProps>;
|
|
157
|
+
|
|
158
|
+
declare const ChessGame: {
|
|
159
|
+
Root: React$1.FC<React$1.PropsWithChildren<RootProps>>;
|
|
160
|
+
Board: React$1.FC<ChessGameProps>;
|
|
161
|
+
Sounds: React$1.FC<SoundsProps>;
|
|
162
|
+
KeyboardControls: React$1.FC<{
|
|
163
|
+
controls?: KeyboardControls;
|
|
164
|
+
}>;
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Returns an object with information about the current state of the game. This can be determined
|
|
169
|
+
* using chess.js instance, but this function is provided for convenience.
|
|
170
|
+
* @param game - The Chess.js instance representing the game.
|
|
171
|
+
* @returns An object with information about the current state of the game.
|
|
172
|
+
*/
|
|
173
|
+
declare const getGameInfo: (game: Chess, orientation: Color) => {
|
|
174
|
+
turn: Color;
|
|
175
|
+
isPlayerTurn: boolean;
|
|
176
|
+
isOpponentTurn: boolean;
|
|
177
|
+
moveNumber: number;
|
|
178
|
+
lastMove: chess_js.Move | undefined;
|
|
179
|
+
isCheck: boolean;
|
|
180
|
+
isCheckmate: boolean;
|
|
181
|
+
isDraw: boolean;
|
|
182
|
+
isStalemate: boolean;
|
|
183
|
+
isThreefoldRepetition: boolean;
|
|
184
|
+
isInsufficientMaterial: boolean;
|
|
185
|
+
isGameOver: boolean;
|
|
186
|
+
isDrawn: boolean;
|
|
187
|
+
hasPlayerWon: boolean;
|
|
188
|
+
hasPlayerLost: boolean;
|
|
189
|
+
};
|
|
190
|
+
type GameInfo = ReturnType<typeof getGameInfo>;
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Smart deep merge for ChessboardOptions that handles different property types appropriately:
|
|
194
|
+
* - Functions: Overwrite (custom functions replace base functions)
|
|
195
|
+
* - Objects: Deep merge (nested objects merge recursively)
|
|
196
|
+
* - Primitives: Overwrite (custom values replace base values)
|
|
197
|
+
*
|
|
198
|
+
* This ensures that computed options (like squareStyles with move highlighting) are preserved
|
|
199
|
+
* while allowing custom options to extend or override them intelligently.
|
|
200
|
+
*
|
|
201
|
+
* @param baseOptions - The computed base options (e.g., computed squareStyles, event handlers)
|
|
202
|
+
* @param customOptions - Custom options provided by the user
|
|
203
|
+
* @returns Intelligently merged ChessboardOptions
|
|
204
|
+
*/
|
|
205
|
+
declare const deepMergeChessboardOptions: (baseOptions: ChessboardOptions, customOptions?: Partial<ChessboardOptions>) => ChessboardOptions;
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Default theme for ChessGame component.
|
|
209
|
+
* These values match the original hardcoded colors for backward compatibility.
|
|
210
|
+
*/
|
|
211
|
+
declare const defaultGameTheme: ChessGameTheme;
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Lichess-inspired theme with green highlights
|
|
215
|
+
*/
|
|
216
|
+
declare const lichessTheme: ChessGameTheme;
|
|
217
|
+
/**
|
|
218
|
+
* Chess.com-inspired theme with green board and yellow highlights
|
|
219
|
+
*/
|
|
220
|
+
declare const chessComTheme: ChessGameTheme;
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Deep merges a partial theme with the default theme.
|
|
224
|
+
* Allows users to override only specific theme properties while keeping defaults for the rest.
|
|
225
|
+
*
|
|
226
|
+
* @param partialTheme - Partial theme with only the properties to override
|
|
227
|
+
* @returns Complete theme with overridden properties merged with defaults
|
|
228
|
+
*
|
|
229
|
+
* @example
|
|
230
|
+
* ```typescript
|
|
231
|
+
* const customTheme = mergeTheme({
|
|
232
|
+
* state: { lastMove: "rgba(100, 200, 100, 0.6)" }
|
|
233
|
+
* });
|
|
234
|
+
* // Returns full theme with only lastMove color changed
|
|
235
|
+
* ```
|
|
236
|
+
*/
|
|
237
|
+
declare const mergeTheme: (partialTheme?: PartialChessGameTheme) => ChessGameTheme;
|
|
238
|
+
/**
|
|
239
|
+
* Deep merges a partial theme with a base theme.
|
|
240
|
+
* Useful when extending an existing theme.
|
|
241
|
+
*
|
|
242
|
+
* @param baseTheme - The base theme to extend
|
|
243
|
+
* @param partialTheme - Partial theme with properties to override
|
|
244
|
+
* @returns Complete theme with overridden properties
|
|
245
|
+
*/
|
|
246
|
+
declare const mergeThemeWith: (baseTheme: ChessGameTheme, partialTheme?: PartialChessGameTheme) => ChessGameTheme;
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Context for ChessGame theme
|
|
250
|
+
*/
|
|
251
|
+
declare const ChessGameThemeContext: React__default.Context<ChessGameTheme>;
|
|
252
|
+
/**
|
|
253
|
+
* Hook to access the current ChessGame theme.
|
|
254
|
+
* Returns the default theme if no ThemeProvider is present.
|
|
255
|
+
*/
|
|
256
|
+
declare const useChessGameTheme: () => ChessGameTheme;
|
|
257
|
+
|
|
258
|
+
declare const themes: {
|
|
259
|
+
readonly default: ChessGameTheme;
|
|
260
|
+
readonly lichess: ChessGameTheme;
|
|
261
|
+
readonly chessCom: ChessGameTheme;
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
export { type BoardTheme, ChessGame, type ChessGameContextType, type ChessGameProps, type ChessGameTheme, ChessGameThemeContext, type DeepPartial, type GameInfo, type IndicatorTheme, KeyboardControls, type PartialChessGameTheme, type RootProps, type Sound, type Sounds, type SoundsProps, type StateTheme, chessComTheme, deepMergeChessboardOptions, defaultGameTheme, lichessTheme, mergeTheme, mergeThemeWith, themes, useChessGame, useChessGameContext, type useChessGameProps, useChessGameTheme };
|