@react-chess-tools/react-chess-puzzle 1.0.0 → 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.cjs CHANGED
@@ -40,11 +40,10 @@ __export(index_exports, {
40
40
  module.exports = __toCommonJS(index_exports);
41
41
 
42
42
  // src/components/ChessPuzzle/parts/Root.tsx
43
- var import_react5 = __toESM(require("react"), 1);
43
+ var import_react4 = __toESM(require("react"), 1);
44
44
 
45
45
  // src/utils/index.ts
46
46
  var import_chess = require("chess.js");
47
- var import_react = __toESM(require("react"), 1);
48
47
  var import_lodash = __toESM(require("lodash"), 1);
49
48
 
50
49
  // src/theme/defaults.ts
@@ -67,7 +66,6 @@ var getOrientation = (puzzle) => {
67
66
  }
68
67
  return game.turn();
69
68
  };
70
- var isClickableElement = (element) => import_react.default.isValidElement(element);
71
69
  var getCustomSquareStyles = (status, hint, isPlayerTurn, game, nextMove, theme = defaultPuzzleTheme) => {
72
70
  const customSquareStyles = {};
73
71
  const lastMove = import_lodash.default.last(game.history({ verbose: true }));
@@ -119,7 +117,7 @@ var stringToMove = (game, move) => {
119
117
  };
120
118
 
121
119
  // src/hooks/useChessPuzzle.ts
122
- var import_react2 = require("react");
120
+ var import_react = require("react");
123
121
 
124
122
  // src/hooks/reducer.ts
125
123
  var initializePuzzle = ({ puzzle }) => {
@@ -172,7 +170,17 @@ var reducer = (state, action) => {
172
170
  status: "in-progress"
173
171
  };
174
172
  case "PLAYER_MOVE": {
175
- const { move } = action.payload;
173
+ const { move, game, solveOnCheckmate } = action.payload;
174
+ if (move && solveOnCheckmate !== false && game.isCheckmate()) {
175
+ return {
176
+ ...state,
177
+ status: "solved",
178
+ nextMove: null,
179
+ hint: "none",
180
+ isPlayerTurn: false,
181
+ onSolveInvoked: false
182
+ };
183
+ }
176
184
  const isMoveRight = [move == null ? void 0 : move.san, move == null ? void 0 : move.lan].includes(
177
185
  (state == null ? void 0 : state.nextMove) || ""
178
186
  );
@@ -224,25 +232,25 @@ var reducer = (state, action) => {
224
232
 
225
233
  // src/hooks/useChessPuzzle.ts
226
234
  var import_react_chess_game2 = require("@react-chess-tools/react-chess-game");
227
- var useChessPuzzle = (puzzle, onSolve, onFail) => {
235
+ var useChessPuzzle = (puzzle, onSolve, onFail, solveOnCheckmate = true) => {
228
236
  var _a;
229
237
  const gameContext = (0, import_react_chess_game2.useChessGameContext)();
230
- const [state, dispatch] = (0, import_react2.useReducer)(reducer, { puzzle }, initializePuzzle);
238
+ const [state, dispatch] = (0, import_react.useReducer)(reducer, { puzzle }, initializePuzzle);
231
239
  const {
232
240
  game,
233
241
  methods: { makeMove, setPosition }
234
242
  } = gameContext;
235
- const changePuzzle = (0, import_react2.useCallback)(
243
+ const changePuzzle = (0, import_react.useCallback)(
236
244
  (puzzle2) => {
237
245
  setPosition(puzzle2.fen, getOrientation(puzzle2));
238
246
  dispatch({ type: "INITIALIZE", payload: { puzzle: puzzle2 } });
239
247
  },
240
248
  [setPosition]
241
249
  );
242
- (0, import_react2.useEffect)(() => {
250
+ (0, import_react.useEffect)(() => {
243
251
  changePuzzle(puzzle);
244
252
  }, [JSON.stringify(puzzle), changePuzzle]);
245
- (0, import_react2.useEffect)(() => {
253
+ (0, import_react.useEffect)(() => {
246
254
  if (gameContext && game.fen() === puzzle.fen && state.needCpuMove) {
247
255
  setTimeout(
248
256
  () => dispatch({
@@ -252,7 +260,7 @@ var useChessPuzzle = (puzzle, onSolve, onFail) => {
252
260
  );
253
261
  }
254
262
  }, [gameContext, state.needCpuMove]);
255
- (0, import_react2.useEffect)(() => {
263
+ (0, import_react.useEffect)(() => {
256
264
  if (state.cpuMove) {
257
265
  makeMove(state.cpuMove);
258
266
  }
@@ -260,13 +268,13 @@ var useChessPuzzle = (puzzle, onSolve, onFail) => {
260
268
  if (!gameContext) {
261
269
  throw new Error("useChessPuzzle must be used within a ChessGameContext");
262
270
  }
263
- const onHint = (0, import_react2.useCallback)(() => {
271
+ const onHint = (0, import_react.useCallback)(() => {
264
272
  dispatch({ type: "TOGGLE_HINT" });
265
273
  }, []);
266
- const resetPuzzle = (0, import_react2.useCallback)(() => {
274
+ const resetPuzzle = (0, import_react.useCallback)(() => {
267
275
  changePuzzle(puzzle);
268
276
  }, [changePuzzle, puzzle]);
269
- const puzzleContext = (0, import_react2.useMemo)(
277
+ const puzzleContext = (0, import_react.useMemo)(
270
278
  () => ({
271
279
  status: state.status,
272
280
  changePuzzle,
@@ -292,7 +300,7 @@ var useChessPuzzle = (puzzle, onSolve, onFail) => {
292
300
  state.currentMoveIndex
293
301
  ]
294
302
  );
295
- (0, import_react2.useEffect)(() => {
303
+ (0, import_react.useEffect)(() => {
296
304
  var _a2, _b, _c;
297
305
  if (((_a2 = game == null ? void 0 : game.history()) == null ? void 0 : _a2.length) <= 0 + (puzzle.makeFirstMove ? 1 : 0)) {
298
306
  return;
@@ -303,7 +311,8 @@ var useChessPuzzle = (puzzle, onSolve, onFail) => {
303
311
  payload: {
304
312
  move: ((_c = (_b = gameContext == null ? void 0 : gameContext.game) == null ? void 0 : _b.history({ verbose: true })) == null ? void 0 : _c.pop()) ?? null,
305
313
  puzzleContext,
306
- game
314
+ game,
315
+ solveOnCheckmate
307
316
  }
308
317
  });
309
318
  dispatch({
@@ -311,13 +320,13 @@ var useChessPuzzle = (puzzle, onSolve, onFail) => {
311
320
  });
312
321
  }
313
322
  }, [(_a = game == null ? void 0 : game.history()) == null ? void 0 : _a.length]);
314
- (0, import_react2.useEffect)(() => {
323
+ (0, import_react.useEffect)(() => {
315
324
  if (state.status === "solved" && !state.onSolveInvoked && onSolve) {
316
325
  onSolve(puzzleContext);
317
326
  dispatch({ type: "MARK_SOLVE_INVOKED" });
318
327
  }
319
328
  }, [state.status, state.onSolveInvoked]);
320
- (0, import_react2.useEffect)(() => {
329
+ (0, import_react.useEffect)(() => {
321
330
  if (state.status === "failed" && !state.onFailInvoked && onFail) {
322
331
  onFail(puzzleContext);
323
332
  dispatch({ type: "MARK_FAIL_INVOKED" });
@@ -330,10 +339,10 @@ var useChessPuzzle = (puzzle, onSolve, onFail) => {
330
339
  var import_react_chess_game3 = require("@react-chess-tools/react-chess-game");
331
340
 
332
341
  // src/hooks/useChessPuzzleContext.ts
333
- var import_react3 = __toESM(require("react"), 1);
334
- var ChessPuzzleContext = import_react3.default.createContext(null);
342
+ var import_react2 = __toESM(require("react"), 1);
343
+ var ChessPuzzleContext = import_react2.default.createContext(null);
335
344
  var useChessPuzzleContext = () => {
336
- const context = import_react3.default.useContext(ChessPuzzleContext);
345
+ const context = import_react2.default.useContext(ChessPuzzleContext);
337
346
  if (!context) {
338
347
  throw new Error(
339
348
  `useChessPuzzleContext must be used within a ChessPuzzle component. Make sure your component is wrapped with <ChessPuzzle.Root> or ensure the ChessPuzzle component is properly rendered in the component tree.`
@@ -343,16 +352,16 @@ var useChessPuzzleContext = () => {
343
352
  };
344
353
 
345
354
  // src/theme/context.tsx
346
- var import_react4 = __toESM(require("react"), 1);
347
- var ChessPuzzleThemeContext = (0, import_react4.createContext)(defaultPuzzleTheme);
355
+ var import_react3 = __toESM(require("react"), 1);
356
+ var ChessPuzzleThemeContext = (0, import_react3.createContext)(defaultPuzzleTheme);
348
357
  var useChessPuzzleTheme = () => {
349
- return (0, import_react4.useContext)(ChessPuzzleThemeContext);
358
+ return (0, import_react3.useContext)(ChessPuzzleThemeContext);
350
359
  };
351
360
  var PuzzleThemeProvider = ({
352
361
  theme,
353
362
  children
354
363
  }) => {
355
- return /* @__PURE__ */ import_react4.default.createElement(ChessPuzzleThemeContext.Provider, { value: theme }, children);
364
+ return /* @__PURE__ */ import_react3.default.createElement(ChessPuzzleThemeContext.Provider, { value: theme }, children);
356
365
  };
357
366
 
358
367
  // src/theme/utils.ts
@@ -369,127 +378,143 @@ var PuzzleRootInner = ({
369
378
  puzzle,
370
379
  onSolve,
371
380
  onFail,
381
+ solveOnCheckmate,
372
382
  children
373
383
  }) => {
374
- const context = useChessPuzzle(puzzle, onSolve, onFail);
375
- return /* @__PURE__ */ import_react5.default.createElement(ChessPuzzleContext.Provider, { value: context }, children);
384
+ const context = useChessPuzzle(puzzle, onSolve, onFail, solveOnCheckmate);
385
+ return /* @__PURE__ */ import_react4.default.createElement(ChessPuzzleContext.Provider, { value: context }, children);
376
386
  };
377
387
  var Root = ({
378
388
  puzzle,
379
389
  onSolve,
380
390
  onFail,
381
391
  theme,
392
+ solveOnCheckmate = true,
382
393
  children
383
394
  }) => {
384
- const mergedTheme = import_react5.default.useMemo(() => mergePuzzleTheme(theme), [theme]);
385
- return /* @__PURE__ */ import_react5.default.createElement(
395
+ const mergedTheme = import_react4.default.useMemo(() => mergePuzzleTheme(theme), [theme]);
396
+ return /* @__PURE__ */ import_react4.default.createElement(
386
397
  import_react_chess_game3.ChessGame.Root,
387
398
  {
388
399
  fen: puzzle.fen,
389
400
  orientation: getOrientation(puzzle),
390
401
  theme: mergedTheme
391
402
  },
392
- /* @__PURE__ */ import_react5.default.createElement(PuzzleThemeProvider, { theme: mergedTheme }, /* @__PURE__ */ import_react5.default.createElement(PuzzleRootInner, { puzzle, onSolve, onFail }, children))
403
+ /* @__PURE__ */ import_react4.default.createElement(PuzzleThemeProvider, { theme: mergedTheme }, /* @__PURE__ */ import_react4.default.createElement(
404
+ PuzzleRootInner,
405
+ {
406
+ puzzle,
407
+ onSolve,
408
+ onFail,
409
+ solveOnCheckmate
410
+ },
411
+ children
412
+ ))
393
413
  );
394
414
  };
415
+ Root.displayName = "ChessPuzzle.Root";
395
416
 
396
417
  // src/components/ChessPuzzle/parts/PuzzleBoard.tsx
397
- var import_react6 = __toESM(require("react"), 1);
418
+ var import_react5 = __toESM(require("react"), 1);
398
419
  var import_react_chess_game4 = require("@react-chess-tools/react-chess-game");
399
- var PuzzleBoard = ({
400
- options = {},
401
- ...rest
402
- }) => {
403
- const puzzleContext = useChessPuzzleContext();
404
- const gameContext = (0, import_react_chess_game4.useChessGameContext)();
405
- const theme = useChessPuzzleTheme();
406
- if (!puzzleContext) {
407
- throw new Error("PuzzleContext not found");
408
- }
409
- if (!gameContext) {
410
- throw new Error("ChessGameContext not found");
420
+ var PuzzleBoard = import_react5.default.forwardRef(
421
+ ({ options, ...rest }, ref) => {
422
+ const puzzleContext = useChessPuzzleContext();
423
+ const gameContext = (0, import_react_chess_game4.useChessGameContext)();
424
+ const theme = useChessPuzzleTheme();
425
+ if (!puzzleContext) {
426
+ throw new Error("PuzzleContext not found");
427
+ }
428
+ if (!gameContext) {
429
+ throw new Error("ChessGameContext not found");
430
+ }
431
+ const { game } = gameContext;
432
+ const { status, hint, isPlayerTurn, nextMove } = puzzleContext;
433
+ const mergedOptions = (0, import_react_chess_game4.deepMergeChessboardOptions)(options || {}, {
434
+ squareStyles: getCustomSquareStyles(
435
+ status,
436
+ hint,
437
+ isPlayerTurn,
438
+ game,
439
+ stringToMove(game, nextMove),
440
+ theme
441
+ )
442
+ });
443
+ return /* @__PURE__ */ import_react5.default.createElement(import_react_chess_game4.ChessGame.Board, { ref, ...rest, options: mergedOptions });
411
444
  }
412
- const { game } = gameContext;
413
- const { status, hint, isPlayerTurn, nextMove } = puzzleContext;
414
- const mergedOptions = (0, import_react_chess_game4.deepMergeChessboardOptions)(options, {
415
- squareStyles: getCustomSquareStyles(
416
- status,
417
- hint,
418
- isPlayerTurn,
419
- game,
420
- stringToMove(game, nextMove),
421
- theme
422
- )
423
- });
424
- return /* @__PURE__ */ import_react6.default.createElement(import_react_chess_game4.ChessGame.Board, { ...rest, options: mergedOptions });
425
- };
445
+ );
446
+ PuzzleBoard.displayName = "ChessPuzzle.PuzzleBoard";
426
447
 
427
448
  // src/components/ChessPuzzle/parts/Reset.tsx
428
- var import_react7 = __toESM(require("react"), 1);
449
+ var import_react6 = __toESM(require("react"), 1);
450
+ var import_react_slot = require("@radix-ui/react-slot");
429
451
  var defaultShowOn = ["failed", "solved"];
430
- var Reset = ({
431
- children,
432
- asChild,
433
- puzzle,
434
- onReset,
435
- showOn = defaultShowOn
436
- }) => {
437
- const puzzleContext = useChessPuzzleContext();
438
- if (!puzzleContext) {
439
- throw new Error("PuzzleContext not found");
440
- }
441
- const { changePuzzle, status } = puzzleContext;
442
- const handleClick = () => {
443
- changePuzzle(puzzle || puzzleContext.puzzle);
444
- onReset == null ? void 0 : onReset(puzzleContext);
445
- };
446
- if (!showOn.includes(status)) {
447
- return null;
448
- }
449
- if (asChild) {
450
- const child = import_react7.default.Children.only(children);
451
- if (isClickableElement(child)) {
452
- return import_react7.default.cloneElement(child, {
453
- onClick: handleClick
454
- });
455
- } else {
456
- throw new Error("Change child must be a clickable element");
452
+ var Reset = import_react6.default.forwardRef(
453
+ ({
454
+ children,
455
+ asChild,
456
+ puzzle,
457
+ onReset,
458
+ showOn = defaultShowOn,
459
+ className,
460
+ ...rest
461
+ }, ref) => {
462
+ const puzzleContext = useChessPuzzleContext();
463
+ if (!puzzleContext) {
464
+ throw new Error("PuzzleContext not found");
465
+ }
466
+ const { changePuzzle, puzzle: contextPuzzle, status } = puzzleContext;
467
+ const handleClick = import_react6.default.useCallback(() => {
468
+ changePuzzle(puzzle || contextPuzzle);
469
+ onReset == null ? void 0 : onReset(puzzleContext);
470
+ }, [changePuzzle, puzzle, contextPuzzle, puzzleContext, onReset]);
471
+ if (!showOn.includes(status)) {
472
+ return null;
457
473
  }
474
+ return asChild ? /* @__PURE__ */ import_react6.default.createElement(import_react_slot.Slot, { ref, onClick: handleClick, className, ...rest }, children) : /* @__PURE__ */ import_react6.default.createElement(
475
+ "button",
476
+ {
477
+ ref,
478
+ type: "button",
479
+ className,
480
+ onClick: handleClick,
481
+ ...rest
482
+ },
483
+ children
484
+ );
458
485
  }
459
- return /* @__PURE__ */ import_react7.default.createElement("button", { type: "button", onClick: handleClick }, children);
460
- };
486
+ );
487
+ Reset.displayName = "ChessPuzzle.Reset";
461
488
 
462
489
  // src/components/ChessPuzzle/parts/Hint.tsx
463
- var import_react8 = __toESM(require("react"), 1);
490
+ var import_react7 = __toESM(require("react"), 1);
491
+ var import_react_slot2 = require("@radix-ui/react-slot");
464
492
  var defaultShowOn2 = ["not-started", "in-progress"];
465
- var Hint = ({
466
- children,
467
- asChild,
468
- showOn = defaultShowOn2
469
- }) => {
493
+ var Hint = import_react7.default.forwardRef(({ children, asChild, showOn = defaultShowOn2, className, ...rest }, ref) => {
470
494
  const puzzleContext = useChessPuzzleContext();
471
495
  if (!puzzleContext) {
472
496
  throw new Error("PuzzleContext not found");
473
497
  }
474
498
  const { onHint, status } = puzzleContext;
475
- const handleClick = () => {
499
+ const handleClick = import_react7.default.useCallback(() => {
476
500
  onHint();
477
- };
501
+ }, [onHint]);
478
502
  if (!showOn.includes(status)) {
479
503
  return null;
480
504
  }
481
- if (asChild) {
482
- const child = import_react8.default.Children.only(children);
483
- if (isClickableElement(child)) {
484
- return import_react8.default.cloneElement(child, {
485
- onClick: handleClick
486
- });
487
- } else {
488
- throw new Error("Change child must be a clickable element");
489
- }
490
- }
491
- return /* @__PURE__ */ import_react8.default.createElement("button", { type: "button", onClick: handleClick }, children);
492
- };
505
+ return asChild ? /* @__PURE__ */ import_react7.default.createElement(import_react_slot2.Slot, { ref, onClick: handleClick, className, ...rest }, children) : /* @__PURE__ */ import_react7.default.createElement(
506
+ "button",
507
+ {
508
+ ref,
509
+ type: "button",
510
+ className,
511
+ onClick: handleClick,
512
+ ...rest
513
+ },
514
+ children
515
+ );
516
+ });
517
+ Hint.displayName = "ChessPuzzle.Hint";
493
518
 
494
519
  // src/components/ChessPuzzle/index.ts
495
520
  var ChessPuzzle = {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/components/ChessPuzzle/parts/Root.tsx","../src/utils/index.ts","../src/theme/defaults.ts","../src/hooks/useChessPuzzle.ts","../src/hooks/reducer.ts","../src/hooks/useChessPuzzleContext.ts","../src/theme/context.tsx","../src/theme/utils.ts","../src/components/ChessPuzzle/parts/PuzzleBoard.tsx","../src/components/ChessPuzzle/parts/Reset.tsx","../src/components/ChessPuzzle/parts/Hint.tsx","../src/components/ChessPuzzle/index.ts"],"sourcesContent":["// Components\nexport { ChessPuzzle } from \"./components/ChessPuzzle\";\n\n// Hooks & Context\nexport { useChessPuzzleContext } from \"./hooks/useChessPuzzleContext\";\nexport type { ChessPuzzleContextType } from \"./hooks/useChessPuzzle\";\n\n// Core Types\nexport type { Status, Hint, Puzzle } from \"./utils\";\n\n// Component Props\nexport type { HintProps } from \"./components/ChessPuzzle/parts/Hint\";\nexport type { ResetProps } from \"./components/ChessPuzzle/parts/Reset\";\nexport type { PuzzleBoardProps } from \"./components/ChessPuzzle/parts/PuzzleBoard\";\nexport type { RootProps } from \"./components/ChessPuzzle/parts/Root\";\n\n// Theme - Types\nexport type {\n ChessPuzzleTheme,\n PuzzleStateTheme,\n PartialChessPuzzleTheme,\n} from \"./theme/types\";\n\n// Theme - Values\nexport { defaultPuzzleTheme } from \"./theme/defaults\";\n\n// Theme - Utilities\nexport { mergePuzzleTheme } from \"./theme/utils\";\nexport { useChessPuzzleTheme, ChessPuzzleThemeContext } from \"./theme/context\";\n","import React from \"react\";\nimport { Puzzle, getOrientation } from \"../../../utils\";\nimport {\n ChessPuzzleContextType,\n useChessPuzzle,\n} from \"../../../hooks/useChessPuzzle\";\nimport { ChessGame } from \"@react-chess-tools/react-chess-game\";\nimport { ChessPuzzleContext } from \"../../../hooks/useChessPuzzleContext\";\nimport { PuzzleThemeProvider } from \"../../../theme/context\";\nimport { mergePuzzleTheme } from \"../../../theme/utils\";\nimport type { PartialChessPuzzleTheme } from \"../../../theme/types\";\n\nexport interface RootProps {\n puzzle: Puzzle;\n onSolve?: (puzzleContext: ChessPuzzleContextType) => void;\n onFail?: (puzzleContext: ChessPuzzleContextType) => void;\n /** Optional theme configuration. Supports partial themes - only override the colors you need. */\n theme?: PartialChessPuzzleTheme;\n}\n\ninterface PuzzleRootInnerProps {\n puzzle: Puzzle;\n onSolve?: (puzzleContext: ChessPuzzleContextType) => void;\n onFail?: (puzzleContext: ChessPuzzleContextType) => void;\n children: React.ReactNode;\n}\n\nconst PuzzleRootInner: React.FC<PuzzleRootInnerProps> = ({\n puzzle,\n onSolve,\n onFail,\n children,\n}) => {\n const context = useChessPuzzle(puzzle, onSolve, onFail);\n\n return (\n <ChessPuzzleContext.Provider value={context}>\n {children}\n </ChessPuzzleContext.Provider>\n );\n};\n\nexport const Root: React.FC<React.PropsWithChildren<RootProps>> = ({\n puzzle,\n onSolve,\n onFail,\n theme,\n children,\n}) => {\n // Merge partial theme with defaults\n const mergedTheme = React.useMemo(() => mergePuzzleTheme(theme), [theme]);\n\n return (\n <ChessGame.Root\n fen={puzzle.fen}\n orientation={getOrientation(puzzle)}\n theme={mergedTheme}\n >\n <PuzzleThemeProvider theme={mergedTheme}>\n <PuzzleRootInner puzzle={puzzle} onSolve={onSolve} onFail={onFail}>\n {children}\n </PuzzleRootInner>\n </PuzzleThemeProvider>\n </ChessGame.Root>\n );\n};\n","import { type Color, Chess, Move } from \"chess.js\";\nimport React, { CSSProperties, ReactElement, ReactNode } from \"react\";\nimport _ from \"lodash\";\nimport type { ChessPuzzleTheme } from \"../theme/types\";\nimport { defaultPuzzleTheme } from \"../theme/defaults\";\n\nexport type Status = \"not-started\" | \"in-progress\" | \"solved\" | \"failed\";\n\nexport type Hint = \"none\" | \"piece\" | \"move\";\n\nexport type Puzzle = {\n fen: string;\n moves: string[];\n // if the first move of the puzzle has to be made by the cpu, as in chess.com puzzles\n makeFirstMove?: boolean;\n};\n\nexport const getOrientation = (puzzle: Puzzle): Color => {\n const fen = puzzle.fen;\n const game = new Chess(fen);\n if (puzzle.makeFirstMove) {\n game.move(puzzle.moves[0]);\n }\n return game.turn();\n};\n\ninterface ClickableElement extends ReactElement {\n props: {\n onClick?: () => void;\n };\n}\n\nexport const isClickableElement = (\n element: ReactNode,\n): element is ClickableElement => React.isValidElement(element);\n\n/**\n * Generates custom square styles for puzzle states based on theme.\n *\n * @param status - Current puzzle status\n * @param hint - Current hint level\n * @param isPlayerTurn - Whether it's the player's turn\n * @param game - Chess.js game instance\n * @param nextMove - The next expected move (for hints)\n * @param theme - Theme configuration (defaults to defaultPuzzleTheme)\n * @returns Record of square names to CSS properties\n */\nexport const getCustomSquareStyles = (\n status: Status,\n hint: Hint,\n isPlayerTurn: boolean,\n game: Chess,\n nextMove?: Move | null,\n theme: ChessPuzzleTheme = defaultPuzzleTheme,\n) => {\n const customSquareStyles: Record<string, CSSProperties> = {};\n\n const lastMove = _.last(game.history({ verbose: true }));\n\n if (status === \"failed\" && lastMove) {\n customSquareStyles[lastMove.from] = {\n backgroundColor: theme.puzzle.failure,\n };\n customSquareStyles[lastMove.to] = {\n backgroundColor: theme.puzzle.failure,\n };\n }\n\n if (\n lastMove &&\n (status === \"solved\" || (status !== \"failed\" && !isPlayerTurn))\n ) {\n customSquareStyles[lastMove.from] = {\n backgroundColor: theme.puzzle.success,\n };\n customSquareStyles[lastMove.to] = {\n backgroundColor: theme.puzzle.success,\n };\n }\n\n if (hint === \"piece\") {\n if (nextMove) {\n customSquareStyles[nextMove.from] = {\n backgroundColor: theme.puzzle.hint,\n };\n }\n }\n\n if (hint === \"move\") {\n if (nextMove) {\n customSquareStyles[nextMove.from] = {\n backgroundColor: theme.puzzle.hint,\n };\n customSquareStyles[nextMove.to] = {\n backgroundColor: theme.puzzle.hint,\n };\n }\n }\n\n return customSquareStyles;\n};\n\nexport const stringToMove = (game: Chess, move: string | null | undefined) => {\n const copy = new Chess(game.fen());\n if (move === null || move === undefined) {\n return null;\n }\n try {\n return copy.move(move);\n } catch (e) {\n return null;\n }\n};\n","import { defaultGameTheme } from \"@react-chess-tools/react-chess-game\";\nimport type { ChessPuzzleTheme } from \"./types\";\n\n/**\n * Default theme for ChessPuzzle component.\n * Extends the default game theme with puzzle-specific colors.\n * These values match the original hardcoded colors for backward compatibility.\n */\nexport const defaultPuzzleTheme: ChessPuzzleTheme = {\n ...defaultGameTheme,\n puzzle: {\n success: \"rgba(172, 206, 89, 0.5)\",\n failure: \"rgba(201, 52, 48, 0.5)\",\n hint: \"rgba(27, 172, 166, 0.5)\",\n },\n};\n","import { useEffect, useReducer, useCallback, useMemo } from \"react\";\nimport { initializePuzzle, reducer } from \"./reducer\";\nimport { getOrientation, type Puzzle, type Hint, type Status } from \"../utils\";\nimport { useChessGameContext } from \"@react-chess-tools/react-chess-game\";\n\nexport type ChessPuzzleContextType = {\n status: Status;\n changePuzzle: (puzzle: Puzzle) => void;\n resetPuzzle: () => void;\n puzzle: Puzzle;\n hint: Hint;\n nextMove?: string | null;\n isPlayerTurn: boolean;\n onHint: () => void;\n puzzleState: Status;\n movesPlayed: number;\n totalMoves: number;\n};\n\nexport const useChessPuzzle = (\n puzzle: Puzzle,\n onSolve?: (puzzleContext: ChessPuzzleContextType) => void,\n onFail?: (puzzleContext: ChessPuzzleContextType) => void,\n): ChessPuzzleContextType => {\n const gameContext = useChessGameContext();\n\n const [state, dispatch] = useReducer(reducer, { puzzle }, initializePuzzle);\n\n const {\n game,\n methods: { makeMove, setPosition },\n } = gameContext;\n\n const changePuzzle = useCallback(\n (puzzle: Puzzle) => {\n setPosition(puzzle.fen, getOrientation(puzzle));\n dispatch({ type: \"INITIALIZE\", payload: { puzzle } });\n },\n [setPosition],\n );\n\n useEffect(() => {\n changePuzzle(puzzle);\n }, [JSON.stringify(puzzle), changePuzzle]);\n\n useEffect(() => {\n if (gameContext && game.fen() === puzzle.fen && state.needCpuMove) {\n setTimeout(\n () =>\n dispatch({\n type: \"CPU_MOVE\",\n }),\n 0,\n );\n }\n }, [gameContext, state.needCpuMove]);\n\n useEffect(() => {\n if (state.cpuMove) {\n makeMove(state.cpuMove);\n }\n }, [state.cpuMove]);\n\n if (!gameContext) {\n throw new Error(\"useChessPuzzle must be used within a ChessGameContext\");\n }\n\n const onHint = useCallback(() => {\n dispatch({ type: \"TOGGLE_HINT\" });\n }, []);\n\n const resetPuzzle = useCallback(() => {\n changePuzzle(puzzle);\n }, [changePuzzle, puzzle]);\n\n const puzzleContext: ChessPuzzleContextType = useMemo(\n () => ({\n status: state.status,\n changePuzzle,\n resetPuzzle,\n puzzle,\n hint: state.hint,\n onHint,\n nextMove: state.nextMove,\n isPlayerTurn: state.isPlayerTurn,\n puzzleState: state.status,\n movesPlayed: state.currentMoveIndex,\n totalMoves: puzzle.moves.length,\n }),\n [\n state.status,\n changePuzzle,\n resetPuzzle,\n puzzle,\n state.hint,\n onHint,\n state.nextMove,\n state.isPlayerTurn,\n state.currentMoveIndex,\n ],\n );\n\n useEffect(() => {\n if (game?.history()?.length <= 0 + (puzzle.makeFirstMove ? 1 : 0)) {\n return;\n }\n if (game.history().length % 2 === (puzzle.makeFirstMove ? 0 : 1)) {\n dispatch({\n type: \"PLAYER_MOVE\",\n payload: {\n move: gameContext?.game?.history({ verbose: true })?.pop() ?? null,\n puzzleContext,\n game: game,\n },\n });\n\n dispatch({\n type: \"CPU_MOVE\",\n });\n }\n }, [game?.history()?.length]);\n\n useEffect(() => {\n if (state.status === \"solved\" && !state.onSolveInvoked && onSolve) {\n onSolve(puzzleContext);\n dispatch({ type: \"MARK_SOLVE_INVOKED\" });\n }\n }, [state.status, state.onSolveInvoked]);\n\n useEffect(() => {\n if (state.status === \"failed\" && !state.onFailInvoked && onFail) {\n onFail(puzzleContext);\n dispatch({ type: \"MARK_FAIL_INVOKED\" });\n }\n }, [state.status, state.onFailInvoked]);\n\n return puzzleContext;\n};\n","import { Chess, Move } from \"chess.js\";\nimport { type Puzzle, type Hint, type Status } from \"../utils\";\nimport { ChessPuzzleContextType } from \"./useChessPuzzle\";\n\nexport type State = {\n puzzle: Puzzle;\n currentMoveIndex: number;\n status: Status;\n cpuMove?: string | null;\n nextMove?: string | null;\n hint: Hint;\n needCpuMove: boolean;\n isPlayerTurn: boolean;\n onSolveInvoked: boolean;\n onFailInvoked: boolean;\n};\n\nexport type Action =\n | {\n type: \"INITIALIZE\";\n payload: {\n puzzle: Puzzle;\n };\n }\n | {\n type: \"RESET\";\n }\n | { type: \"TOGGLE_HINT\" }\n | {\n type: \"CPU_MOVE\";\n }\n | {\n type: \"PLAYER_MOVE\";\n payload: {\n move?: Move | null;\n puzzleContext: ChessPuzzleContextType;\n game: Chess;\n };\n }\n | { type: \"MARK_SOLVE_INVOKED\" }\n | { type: \"MARK_FAIL_INVOKED\" };\n\nexport const initializePuzzle = ({ puzzle }: { puzzle: Puzzle }): State => {\n return {\n puzzle,\n currentMoveIndex: 0,\n status: \"not-started\",\n nextMove: puzzle.moves[0],\n hint: \"none\",\n cpuMove: null,\n needCpuMove: !!puzzle.makeFirstMove,\n isPlayerTurn: !puzzle.makeFirstMove,\n onSolveInvoked: false,\n onFailInvoked: false,\n };\n};\n\nexport const reducer = (state: State, action: Action): State => {\n switch (action.type) {\n case \"INITIALIZE\":\n return {\n ...state,\n ...initializePuzzle(action.payload),\n };\n case \"RESET\":\n return {\n ...state,\n ...initializePuzzle({\n puzzle: state.puzzle,\n }),\n };\n case \"TOGGLE_HINT\":\n if (state.hint === \"none\") {\n return { ...state, hint: \"piece\" };\n }\n return { ...state, hint: \"move\" };\n case \"CPU_MOVE\":\n if (state.isPlayerTurn) {\n return state;\n }\n if ([\"solved\", \"failed\"].includes(state.status)) {\n return state;\n }\n\n return {\n ...state,\n currentMoveIndex: state.currentMoveIndex + 1,\n cpuMove: state.puzzle.moves[state.currentMoveIndex],\n nextMove:\n state.currentMoveIndex < state.puzzle.moves.length - 1\n ? state.puzzle.moves[state.currentMoveIndex + 1]\n : null,\n needCpuMove: false,\n isPlayerTurn: true,\n status: \"in-progress\",\n };\n\n case \"PLAYER_MOVE\": {\n const { move } = action.payload;\n\n const isMoveRight = [move?.san, move?.lan].includes(\n state?.nextMove || \"\",\n );\n const isPuzzleSolved =\n state.currentMoveIndex === state.puzzle.moves.length - 1;\n\n if (!isMoveRight) {\n return {\n ...state,\n status: \"failed\",\n nextMove: null,\n hint: \"none\",\n isPlayerTurn: false,\n onFailInvoked: false,\n };\n }\n\n if (isPuzzleSolved) {\n return {\n ...state,\n status: \"solved\",\n nextMove: null,\n hint: \"none\",\n isPlayerTurn: false,\n onSolveInvoked: false,\n };\n }\n\n return {\n ...state,\n hint: \"none\",\n currentMoveIndex: state.currentMoveIndex + 1,\n nextMove: state.puzzle.moves[state.currentMoveIndex + 1],\n status: \"in-progress\",\n needCpuMove: true,\n isPlayerTurn: false,\n };\n }\n\n case \"MARK_SOLVE_INVOKED\":\n return {\n ...state,\n onSolveInvoked: true,\n };\n\n case \"MARK_FAIL_INVOKED\":\n return {\n ...state,\n onFailInvoked: true,\n };\n\n default:\n return state;\n }\n};\n","import React from \"react\";\nimport { useChessPuzzle } from \"./useChessPuzzle\";\n\nexport const ChessPuzzleContext = React.createContext<ReturnType<\n typeof useChessPuzzle\n> | null>(null);\n\nexport const useChessPuzzleContext = () => {\n const context = React.useContext(ChessPuzzleContext);\n if (!context) {\n throw new Error(\n `useChessPuzzleContext must be used within a ChessPuzzle component. Make sure your component is wrapped with <ChessPuzzle.Root> or ensure the ChessPuzzle component is properly rendered in the component tree.`,\n );\n }\n return context;\n};\n","import React, { createContext, useContext } from \"react\";\nimport type { ChessPuzzleTheme } from \"./types\";\nimport { defaultPuzzleTheme } from \"./defaults\";\n\n/**\n * Context for ChessPuzzle theme\n */\nexport const ChessPuzzleThemeContext =\n createContext<ChessPuzzleTheme>(defaultPuzzleTheme);\n\n/**\n * Hook to access the current ChessPuzzle theme.\n * Returns the default puzzle theme if no ThemeProvider is present.\n */\nexport const useChessPuzzleTheme = (): ChessPuzzleTheme => {\n return useContext(ChessPuzzleThemeContext);\n};\n\nexport interface PuzzleThemeProviderProps {\n theme: ChessPuzzleTheme;\n children: React.ReactNode;\n}\n\n/**\n * Internal provider component used by Puzzle Root when a theme prop is provided.\n */\nexport const PuzzleThemeProvider: React.FC<PuzzleThemeProviderProps> = ({\n theme,\n children,\n}) => {\n return (\n <ChessPuzzleThemeContext.Provider value={theme}>\n {children}\n </ChessPuzzleThemeContext.Provider>\n );\n};\n","import { merge } from \"lodash\";\nimport type { ChessPuzzleTheme, PartialChessPuzzleTheme } from \"./types\";\nimport { defaultPuzzleTheme } from \"./defaults\";\n\n/**\n * Deep merges a partial puzzle theme with the default puzzle 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 puzzle theme with overridden properties merged with defaults\n *\n * @example\n * ```typescript\n * const customTheme = mergePuzzleTheme({\n * puzzle: { hint: \"rgba(0, 255, 255, 0.5)\" }\n * });\n * // Returns full puzzle theme with only hint color changed\n * ```\n */\nexport const mergePuzzleTheme = (\n partialTheme?: PartialChessPuzzleTheme,\n): ChessPuzzleTheme => {\n if (!partialTheme) {\n return { ...defaultPuzzleTheme };\n }\n\n return merge({}, defaultPuzzleTheme, partialTheme);\n};\n","import React from \"react\";\nimport {\n ChessGame,\n deepMergeChessboardOptions,\n useChessGameContext,\n} from \"@react-chess-tools/react-chess-game\";\nimport { getCustomSquareStyles, stringToMove } from \"../../../utils\";\nimport { useChessPuzzleContext } from \"../../..\";\nimport { useChessPuzzleTheme } from \"../../../theme/context\";\n\nexport interface PuzzleBoardProps extends React.ComponentProps<\n typeof ChessGame.Board\n> {}\n\nexport const PuzzleBoard: React.FC<PuzzleBoardProps> = ({\n options = {},\n ...rest\n}) => {\n const puzzleContext = useChessPuzzleContext();\n const gameContext = useChessGameContext();\n const theme = useChessPuzzleTheme();\n\n if (!puzzleContext) {\n throw new Error(\"PuzzleContext not found\");\n }\n if (!gameContext) {\n throw new Error(\"ChessGameContext not found\");\n }\n\n const { game } = gameContext;\n const { status, hint, isPlayerTurn, nextMove } = puzzleContext;\n\n const mergedOptions = deepMergeChessboardOptions(options, {\n squareStyles: getCustomSquareStyles(\n status,\n hint,\n isPlayerTurn,\n game,\n stringToMove(game, nextMove),\n theme,\n ),\n });\n\n return <ChessGame.Board {...rest} options={mergedOptions} />;\n};\n","import React from \"react\";\nimport { isClickableElement, type Puzzle, type Status } from \"../../../utils\";\nimport { useChessPuzzleContext, type ChessPuzzleContextType } from \"../../..\";\n\nexport interface ResetProps {\n asChild?: boolean;\n puzzle?: Puzzle;\n onReset?: (puzzleContext: ChessPuzzleContextType) => void;\n showOn?: Status[];\n}\n\nconst defaultShowOn: Status[] = [\"failed\", \"solved\"];\n\nexport const Reset: React.FC<React.PropsWithChildren<ResetProps>> = ({\n children,\n asChild,\n puzzle,\n onReset,\n showOn = defaultShowOn,\n}) => {\n const puzzleContext = useChessPuzzleContext();\n if (!puzzleContext) {\n throw new Error(\"PuzzleContext not found\");\n }\n const { changePuzzle, status } = puzzleContext;\n const handleClick = () => {\n changePuzzle(puzzle || puzzleContext.puzzle);\n onReset?.(puzzleContext);\n };\n\n if (!showOn.includes(status)) {\n return null;\n }\n\n if (asChild) {\n const child = React.Children.only(children);\n if (isClickableElement(child)) {\n return React.cloneElement(child, {\n onClick: handleClick,\n });\n } else {\n throw new Error(\"Change child must be a clickable element\");\n }\n }\n\n return (\n <button type=\"button\" onClick={handleClick}>\n {children}\n </button>\n );\n};\n","import React from \"react\";\nimport { Status, isClickableElement } from \"../../../utils\";\nimport { useChessPuzzleContext } from \"../../..\";\n\nexport interface HintProps {\n asChild?: boolean;\n showOn?: Status[];\n}\n\nconst defaultShowOn: Status[] = [\"not-started\", \"in-progress\"];\n\nexport const Hint: React.FC<React.PropsWithChildren<HintProps>> = ({\n children,\n asChild,\n showOn = defaultShowOn,\n}) => {\n const puzzleContext = useChessPuzzleContext();\n if (!puzzleContext) {\n throw new Error(\"PuzzleContext not found\");\n }\n const { onHint, status } = puzzleContext;\n const handleClick = () => {\n onHint();\n };\n\n if (!showOn.includes(status)) {\n return null;\n }\n\n if (asChild) {\n const child = React.Children.only(children);\n if (isClickableElement(child)) {\n return React.cloneElement(child, {\n onClick: handleClick,\n });\n } else {\n throw new Error(\"Change child must be a clickable element\");\n }\n }\n\n return (\n <button type=\"button\" onClick={handleClick}>\n {children}\n </button>\n );\n};\n","import { Root } from \"./parts/Root\";\nimport { PuzzleBoard } from \"./parts/PuzzleBoard\";\nimport { Reset } from \"./parts/Reset\";\nimport { Hint } from \"./parts/Hint\";\n\nexport const ChessPuzzle = {\n Root,\n Board: PuzzleBoard,\n Reset,\n Hint,\n};\n"],"mappings":"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","names":["import_react","React","_","import_react","import_react_chess_game","puzzle","_a","import_react_chess_game","import_react","React","import_react","React","import_lodash","React","import_react","import_react_chess_game","React","import_react","React","import_react","defaultShowOn","React"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/components/ChessPuzzle/parts/Root.tsx","../src/utils/index.ts","../src/theme/defaults.ts","../src/hooks/useChessPuzzle.ts","../src/hooks/reducer.ts","../src/hooks/useChessPuzzleContext.ts","../src/theme/context.tsx","../src/theme/utils.ts","../src/components/ChessPuzzle/parts/PuzzleBoard.tsx","../src/components/ChessPuzzle/parts/Reset.tsx","../src/components/ChessPuzzle/parts/Hint.tsx","../src/components/ChessPuzzle/index.ts"],"sourcesContent":["// Components\nexport { ChessPuzzle } from \"./components/ChessPuzzle\";\n\n// Hooks & Context\nexport { useChessPuzzleContext } from \"./hooks/useChessPuzzleContext\";\nexport type { ChessPuzzleContextType } from \"./hooks/useChessPuzzle\";\n\n// Core Types\nexport type { Status, Hint, Puzzle } from \"./utils\";\n\n// Component Props\nexport type { HintProps } from \"./components/ChessPuzzle/parts/Hint\";\nexport type { ResetProps } from \"./components/ChessPuzzle/parts/Reset\";\nexport type { PuzzleBoardProps } from \"./components/ChessPuzzle/parts/PuzzleBoard\";\nexport type { RootProps } from \"./components/ChessPuzzle/parts/Root\";\n\n// Theme - Types\nexport type {\n ChessPuzzleTheme,\n PuzzleStateTheme,\n PartialChessPuzzleTheme,\n} from \"./theme/types\";\n\n// Theme - Values\nexport { defaultPuzzleTheme } from \"./theme/defaults\";\n\n// Theme - Utilities\nexport { mergePuzzleTheme } from \"./theme/utils\";\nexport { useChessPuzzleTheme, ChessPuzzleThemeContext } from \"./theme/context\";\n","import React from \"react\";\nimport { Puzzle, getOrientation } from \"../../../utils\";\nimport {\n ChessPuzzleContextType,\n useChessPuzzle,\n} from \"../../../hooks/useChessPuzzle\";\nimport { ChessGame } from \"@react-chess-tools/react-chess-game\";\nimport { ChessPuzzleContext } from \"../../../hooks/useChessPuzzleContext\";\nimport { PuzzleThemeProvider } from \"../../../theme/context\";\nimport { mergePuzzleTheme } from \"../../../theme/utils\";\nimport type { PartialChessPuzzleTheme } from \"../../../theme/types\";\n\nexport interface RootProps {\n puzzle: Puzzle;\n onSolve?: (puzzleContext: ChessPuzzleContextType) => void;\n onFail?: (puzzleContext: ChessPuzzleContextType) => void;\n /** Optional theme configuration. Supports partial themes - only override the colors you need. */\n theme?: PartialChessPuzzleTheme;\n /** When true, any checkmate move solves the puzzle (not just the canonical solution). Defaults to true. */\n solveOnCheckmate?: boolean;\n}\n\ninterface PuzzleRootInnerProps {\n puzzle: Puzzle;\n onSolve?: (puzzleContext: ChessPuzzleContextType) => void;\n onFail?: (puzzleContext: ChessPuzzleContextType) => void;\n solveOnCheckmate: boolean;\n children: React.ReactNode;\n}\n\nconst PuzzleRootInner: React.FC<PuzzleRootInnerProps> = ({\n puzzle,\n onSolve,\n onFail,\n solveOnCheckmate,\n children,\n}) => {\n const context = useChessPuzzle(puzzle, onSolve, onFail, solveOnCheckmate);\n\n return (\n <ChessPuzzleContext.Provider value={context}>\n {children}\n </ChessPuzzleContext.Provider>\n );\n};\n\nexport const Root: React.FC<React.PropsWithChildren<RootProps>> = ({\n puzzle,\n onSolve,\n onFail,\n theme,\n solveOnCheckmate = true,\n children,\n}) => {\n // Merge partial theme with defaults\n const mergedTheme = React.useMemo(() => mergePuzzleTheme(theme), [theme]);\n\n return (\n <ChessGame.Root\n fen={puzzle.fen}\n orientation={getOrientation(puzzle)}\n theme={mergedTheme}\n >\n <PuzzleThemeProvider theme={mergedTheme}>\n <PuzzleRootInner\n puzzle={puzzle}\n onSolve={onSolve}\n onFail={onFail}\n solveOnCheckmate={solveOnCheckmate}\n >\n {children}\n </PuzzleRootInner>\n </PuzzleThemeProvider>\n </ChessGame.Root>\n );\n};\n\nRoot.displayName = \"ChessPuzzle.Root\";\n","import { type Color, Chess, Move } from \"chess.js\";\nimport { type CSSProperties } from \"react\";\nimport _ from \"lodash\";\nimport type { ChessPuzzleTheme } from \"../theme/types\";\nimport { defaultPuzzleTheme } from \"../theme/defaults\";\n\nexport type Status = \"not-started\" | \"in-progress\" | \"solved\" | \"failed\";\n\nexport type Hint = \"none\" | \"piece\" | \"move\";\n\nexport type Puzzle = {\n fen: string;\n moves: string[];\n // if the first move of the puzzle has to be made by the cpu, as in chess.com puzzles\n makeFirstMove?: boolean;\n};\n\nexport const getOrientation = (puzzle: Puzzle): Color => {\n const fen = puzzle.fen;\n const game = new Chess(fen);\n if (puzzle.makeFirstMove) {\n game.move(puzzle.moves[0]);\n }\n return game.turn();\n};\n\n/**\n * Generates custom square styles for puzzle states based on theme.\n *\n * @param status - Current puzzle status\n * @param hint - Current hint level\n * @param isPlayerTurn - Whether it's the player's turn\n * @param game - Chess.js game instance\n * @param nextMove - The next expected move (for hints)\n * @param theme - Theme configuration (defaults to defaultPuzzleTheme)\n * @returns Record of square names to CSS properties\n */\nexport const getCustomSquareStyles = (\n status: Status,\n hint: Hint,\n isPlayerTurn: boolean,\n game: Chess,\n nextMove?: Move | null,\n theme: ChessPuzzleTheme = defaultPuzzleTheme,\n) => {\n const customSquareStyles: Record<string, CSSProperties> = {};\n\n const lastMove = _.last(game.history({ verbose: true }));\n\n if (status === \"failed\" && lastMove) {\n customSquareStyles[lastMove.from] = {\n backgroundColor: theme.puzzle.failure,\n };\n customSquareStyles[lastMove.to] = {\n backgroundColor: theme.puzzle.failure,\n };\n }\n\n if (\n lastMove &&\n (status === \"solved\" || (status !== \"failed\" && !isPlayerTurn))\n ) {\n customSquareStyles[lastMove.from] = {\n backgroundColor: theme.puzzle.success,\n };\n customSquareStyles[lastMove.to] = {\n backgroundColor: theme.puzzle.success,\n };\n }\n\n if (hint === \"piece\") {\n if (nextMove) {\n customSquareStyles[nextMove.from] = {\n backgroundColor: theme.puzzle.hint,\n };\n }\n }\n\n if (hint === \"move\") {\n if (nextMove) {\n customSquareStyles[nextMove.from] = {\n backgroundColor: theme.puzzle.hint,\n };\n customSquareStyles[nextMove.to] = {\n backgroundColor: theme.puzzle.hint,\n };\n }\n }\n\n return customSquareStyles;\n};\n\nexport const stringToMove = (game: Chess, move: string | null | undefined) => {\n const copy = new Chess(game.fen());\n if (move === null || move === undefined) {\n return null;\n }\n try {\n return copy.move(move);\n } catch (e) {\n return null;\n }\n};\n","import { defaultGameTheme } from \"@react-chess-tools/react-chess-game\";\nimport type { ChessPuzzleTheme } from \"./types\";\n\n/**\n * Default theme for ChessPuzzle component.\n * Extends the default game theme with puzzle-specific colors.\n * These values match the original hardcoded colors for backward compatibility.\n */\nexport const defaultPuzzleTheme: ChessPuzzleTheme = {\n ...defaultGameTheme,\n puzzle: {\n success: \"rgba(172, 206, 89, 0.5)\",\n failure: \"rgba(201, 52, 48, 0.5)\",\n hint: \"rgba(27, 172, 166, 0.5)\",\n },\n};\n","import { useEffect, useReducer, useCallback, useMemo } from \"react\";\nimport { initializePuzzle, reducer } from \"./reducer\";\nimport { getOrientation, type Puzzle, type Hint, type Status } from \"../utils\";\nimport { useChessGameContext } from \"@react-chess-tools/react-chess-game\";\n\nexport type ChessPuzzleContextType = {\n status: Status;\n changePuzzle: (puzzle: Puzzle) => void;\n resetPuzzle: () => void;\n puzzle: Puzzle;\n hint: Hint;\n nextMove?: string | null;\n isPlayerTurn: boolean;\n onHint: () => void;\n puzzleState: Status;\n movesPlayed: number;\n totalMoves: number;\n};\n\nexport const useChessPuzzle = (\n puzzle: Puzzle,\n onSolve?: (puzzleContext: ChessPuzzleContextType) => void,\n onFail?: (puzzleContext: ChessPuzzleContextType) => void,\n solveOnCheckmate: boolean = true,\n): ChessPuzzleContextType => {\n const gameContext = useChessGameContext();\n\n const [state, dispatch] = useReducer(reducer, { puzzle }, initializePuzzle);\n\n const {\n game,\n methods: { makeMove, setPosition },\n } = gameContext;\n\n const changePuzzle = useCallback(\n (puzzle: Puzzle) => {\n setPosition(puzzle.fen, getOrientation(puzzle));\n dispatch({ type: \"INITIALIZE\", payload: { puzzle } });\n },\n [setPosition],\n );\n\n useEffect(() => {\n changePuzzle(puzzle);\n }, [JSON.stringify(puzzle), changePuzzle]);\n\n useEffect(() => {\n if (gameContext && game.fen() === puzzle.fen && state.needCpuMove) {\n setTimeout(\n () =>\n dispatch({\n type: \"CPU_MOVE\",\n }),\n 0,\n );\n }\n }, [gameContext, state.needCpuMove]);\n\n useEffect(() => {\n if (state.cpuMove) {\n makeMove(state.cpuMove);\n }\n }, [state.cpuMove]);\n\n if (!gameContext) {\n throw new Error(\"useChessPuzzle must be used within a ChessGameContext\");\n }\n\n const onHint = useCallback(() => {\n dispatch({ type: \"TOGGLE_HINT\" });\n }, []);\n\n const resetPuzzle = useCallback(() => {\n changePuzzle(puzzle);\n }, [changePuzzle, puzzle]);\n\n const puzzleContext: ChessPuzzleContextType = useMemo(\n () => ({\n status: state.status,\n changePuzzle,\n resetPuzzle,\n puzzle,\n hint: state.hint,\n onHint,\n nextMove: state.nextMove,\n isPlayerTurn: state.isPlayerTurn,\n puzzleState: state.status,\n movesPlayed: state.currentMoveIndex,\n totalMoves: puzzle.moves.length,\n }),\n [\n state.status,\n changePuzzle,\n resetPuzzle,\n puzzle,\n state.hint,\n onHint,\n state.nextMove,\n state.isPlayerTurn,\n state.currentMoveIndex,\n ],\n );\n\n useEffect(() => {\n if (game?.history()?.length <= 0 + (puzzle.makeFirstMove ? 1 : 0)) {\n return;\n }\n if (game.history().length % 2 === (puzzle.makeFirstMove ? 0 : 1)) {\n dispatch({\n type: \"PLAYER_MOVE\",\n payload: {\n move: gameContext?.game?.history({ verbose: true })?.pop() ?? null,\n puzzleContext,\n game: game,\n solveOnCheckmate,\n },\n });\n\n dispatch({\n type: \"CPU_MOVE\",\n });\n }\n }, [game?.history()?.length]);\n\n useEffect(() => {\n if (state.status === \"solved\" && !state.onSolveInvoked && onSolve) {\n onSolve(puzzleContext);\n dispatch({ type: \"MARK_SOLVE_INVOKED\" });\n }\n }, [state.status, state.onSolveInvoked]);\n\n useEffect(() => {\n if (state.status === \"failed\" && !state.onFailInvoked && onFail) {\n onFail(puzzleContext);\n dispatch({ type: \"MARK_FAIL_INVOKED\" });\n }\n }, [state.status, state.onFailInvoked]);\n\n return puzzleContext;\n};\n","import { Chess, Move } from \"chess.js\";\nimport { type Puzzle, type Hint, type Status } from \"../utils\";\nimport { ChessPuzzleContextType } from \"./useChessPuzzle\";\n\nexport type State = {\n puzzle: Puzzle;\n currentMoveIndex: number;\n status: Status;\n cpuMove?: string | null;\n nextMove?: string | null;\n hint: Hint;\n needCpuMove: boolean;\n isPlayerTurn: boolean;\n onSolveInvoked: boolean;\n onFailInvoked: boolean;\n};\n\nexport type Action =\n | {\n type: \"INITIALIZE\";\n payload: {\n puzzle: Puzzle;\n };\n }\n | {\n type: \"RESET\";\n }\n | { type: \"TOGGLE_HINT\" }\n | {\n type: \"CPU_MOVE\";\n }\n | {\n type: \"PLAYER_MOVE\";\n payload: {\n move?: Move | null;\n puzzleContext: ChessPuzzleContextType;\n game: Chess;\n solveOnCheckmate?: boolean;\n };\n }\n | { type: \"MARK_SOLVE_INVOKED\" }\n | { type: \"MARK_FAIL_INVOKED\" };\n\nexport const initializePuzzle = ({ puzzle }: { puzzle: Puzzle }): State => {\n return {\n puzzle,\n currentMoveIndex: 0,\n status: \"not-started\",\n nextMove: puzzle.moves[0],\n hint: \"none\",\n cpuMove: null,\n needCpuMove: !!puzzle.makeFirstMove,\n isPlayerTurn: !puzzle.makeFirstMove,\n onSolveInvoked: false,\n onFailInvoked: false,\n };\n};\n\nexport const reducer = (state: State, action: Action): State => {\n switch (action.type) {\n case \"INITIALIZE\":\n return {\n ...state,\n ...initializePuzzle(action.payload),\n };\n case \"RESET\":\n return {\n ...state,\n ...initializePuzzle({\n puzzle: state.puzzle,\n }),\n };\n case \"TOGGLE_HINT\":\n if (state.hint === \"none\") {\n return { ...state, hint: \"piece\" };\n }\n return { ...state, hint: \"move\" };\n case \"CPU_MOVE\":\n if (state.isPlayerTurn) {\n return state;\n }\n if ([\"solved\", \"failed\"].includes(state.status)) {\n return state;\n }\n\n return {\n ...state,\n currentMoveIndex: state.currentMoveIndex + 1,\n cpuMove: state.puzzle.moves[state.currentMoveIndex],\n nextMove:\n state.currentMoveIndex < state.puzzle.moves.length - 1\n ? state.puzzle.moves[state.currentMoveIndex + 1]\n : null,\n needCpuMove: false,\n isPlayerTurn: true,\n status: \"in-progress\",\n };\n\n case \"PLAYER_MOVE\": {\n const { move, game, solveOnCheckmate } = action.payload;\n\n if (move && solveOnCheckmate !== false && game.isCheckmate()) {\n return {\n ...state,\n status: \"solved\",\n nextMove: null,\n hint: \"none\",\n isPlayerTurn: false,\n onSolveInvoked: false,\n };\n }\n\n const isMoveRight = [move?.san, move?.lan].includes(\n state?.nextMove || \"\",\n );\n const isPuzzleSolved =\n state.currentMoveIndex === state.puzzle.moves.length - 1;\n\n if (!isMoveRight) {\n return {\n ...state,\n status: \"failed\",\n nextMove: null,\n hint: \"none\",\n isPlayerTurn: false,\n onFailInvoked: false,\n };\n }\n\n if (isPuzzleSolved) {\n return {\n ...state,\n status: \"solved\",\n nextMove: null,\n hint: \"none\",\n isPlayerTurn: false,\n onSolveInvoked: false,\n };\n }\n\n return {\n ...state,\n hint: \"none\",\n currentMoveIndex: state.currentMoveIndex + 1,\n nextMove: state.puzzle.moves[state.currentMoveIndex + 1],\n status: \"in-progress\",\n needCpuMove: true,\n isPlayerTurn: false,\n };\n }\n\n case \"MARK_SOLVE_INVOKED\":\n return {\n ...state,\n onSolveInvoked: true,\n };\n\n case \"MARK_FAIL_INVOKED\":\n return {\n ...state,\n onFailInvoked: true,\n };\n\n default:\n return state;\n }\n};\n","import React from \"react\";\nimport { useChessPuzzle } from \"./useChessPuzzle\";\n\nexport const ChessPuzzleContext = React.createContext<ReturnType<\n typeof useChessPuzzle\n> | null>(null);\n\nexport const useChessPuzzleContext = () => {\n const context = React.useContext(ChessPuzzleContext);\n if (!context) {\n throw new Error(\n `useChessPuzzleContext must be used within a ChessPuzzle component. Make sure your component is wrapped with <ChessPuzzle.Root> or ensure the ChessPuzzle component is properly rendered in the component tree.`,\n );\n }\n return context;\n};\n","import React, { createContext, useContext } from \"react\";\nimport type { ChessPuzzleTheme } from \"./types\";\nimport { defaultPuzzleTheme } from \"./defaults\";\n\n/**\n * Context for ChessPuzzle theme\n */\nexport const ChessPuzzleThemeContext =\n createContext<ChessPuzzleTheme>(defaultPuzzleTheme);\n\n/**\n * Hook to access the current ChessPuzzle theme.\n * Returns the default puzzle theme if no ThemeProvider is present.\n */\nexport const useChessPuzzleTheme = (): ChessPuzzleTheme => {\n return useContext(ChessPuzzleThemeContext);\n};\n\nexport interface PuzzleThemeProviderProps {\n theme: ChessPuzzleTheme;\n children: React.ReactNode;\n}\n\n/**\n * Internal provider component used by Puzzle Root when a theme prop is provided.\n */\nexport const PuzzleThemeProvider: React.FC<PuzzleThemeProviderProps> = ({\n theme,\n children,\n}) => {\n return (\n <ChessPuzzleThemeContext.Provider value={theme}>\n {children}\n </ChessPuzzleThemeContext.Provider>\n );\n};\n","import { merge } from \"lodash\";\nimport type { ChessPuzzleTheme, PartialChessPuzzleTheme } from \"./types\";\nimport { defaultPuzzleTheme } from \"./defaults\";\n\n/**\n * Deep merges a partial puzzle theme with the default puzzle 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 puzzle theme with overridden properties merged with defaults\n *\n * @example\n * ```typescript\n * const customTheme = mergePuzzleTheme({\n * puzzle: { hint: \"rgba(0, 255, 255, 0.5)\" }\n * });\n * // Returns full puzzle theme with only hint color changed\n * ```\n */\nexport const mergePuzzleTheme = (\n partialTheme?: PartialChessPuzzleTheme,\n): ChessPuzzleTheme => {\n if (!partialTheme) {\n return { ...defaultPuzzleTheme };\n }\n\n return merge({}, defaultPuzzleTheme, partialTheme);\n};\n","import React from \"react\";\nimport {\n ChessGame,\n deepMergeChessboardOptions,\n useChessGameContext,\n} from \"@react-chess-tools/react-chess-game\";\nimport { getCustomSquareStyles, stringToMove } from \"../../../utils\";\nimport { useChessPuzzleContext } from \"../../..\";\nimport { useChessPuzzleTheme } from \"../../../theme/context\";\n\nexport interface PuzzleBoardProps extends React.ComponentProps<\n typeof ChessGame.Board\n> {}\n\nexport const PuzzleBoard = React.forwardRef<HTMLDivElement, PuzzleBoardProps>(\n ({ options, ...rest }, ref) => {\n const puzzleContext = useChessPuzzleContext();\n const gameContext = useChessGameContext();\n const theme = useChessPuzzleTheme();\n\n if (!puzzleContext) {\n throw new Error(\"PuzzleContext not found\");\n }\n if (!gameContext) {\n throw new Error(\"ChessGameContext not found\");\n }\n\n const { game } = gameContext;\n const { status, hint, isPlayerTurn, nextMove } = puzzleContext;\n\n const mergedOptions = deepMergeChessboardOptions(options || {}, {\n squareStyles: getCustomSquareStyles(\n status,\n hint,\n isPlayerTurn,\n game,\n stringToMove(game, nextMove),\n theme,\n ),\n });\n\n return <ChessGame.Board ref={ref} {...rest} options={mergedOptions} />;\n },\n);\n\nPuzzleBoard.displayName = \"ChessPuzzle.PuzzleBoard\";\n","import React from \"react\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { type Puzzle, type Status } from \"../../../utils\";\nimport { useChessPuzzleContext, type ChessPuzzleContextType } from \"../../..\";\n\nexport interface ResetProps extends Omit<\n React.ButtonHTMLAttributes<HTMLButtonElement>,\n \"onReset\"\n> {\n asChild?: boolean;\n puzzle?: Puzzle;\n onReset?: (puzzleContext: ChessPuzzleContextType) => void;\n /**\n * The puzzle statuses in which the reset button should be visible.\n * @default [\"failed\", \"solved\"]\n */\n showOn?: Status[];\n}\n\nconst defaultShowOn: Status[] = [\"failed\", \"solved\"];\n\nexport const Reset = React.forwardRef<\n HTMLElement,\n React.PropsWithChildren<ResetProps>\n>(\n (\n {\n children,\n asChild,\n puzzle,\n onReset,\n showOn = defaultShowOn,\n className,\n ...rest\n },\n ref,\n ) => {\n const puzzleContext = useChessPuzzleContext();\n if (!puzzleContext) {\n throw new Error(\"PuzzleContext not found\");\n }\n const { changePuzzle, puzzle: contextPuzzle, status } = puzzleContext;\n\n const handleClick = React.useCallback(() => {\n changePuzzle(puzzle || contextPuzzle);\n onReset?.(puzzleContext);\n }, [changePuzzle, puzzle, contextPuzzle, puzzleContext, onReset]);\n\n if (!showOn.includes(status)) {\n return null;\n }\n\n return asChild ? (\n <Slot ref={ref} onClick={handleClick} className={className} {...rest}>\n {children}\n </Slot>\n ) : (\n <button\n ref={ref as React.RefObject<HTMLButtonElement>}\n type=\"button\"\n className={className}\n onClick={handleClick}\n {...rest}\n >\n {children}\n </button>\n );\n },\n);\n\nReset.displayName = \"ChessPuzzle.Reset\";\n","import React from \"react\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { Status } from \"../../../utils\";\nimport { useChessPuzzleContext } from \"../../..\";\n\nexport interface HintProps extends Omit<\n React.ButtonHTMLAttributes<HTMLButtonElement>,\n \"onClick\"\n> {\n asChild?: boolean;\n /**\n * The puzzle statuses in which the hint button should be visible.\n * @default [\"not-started\", \"in-progress\"]\n */\n showOn?: Status[];\n}\n\nconst defaultShowOn: Status[] = [\"not-started\", \"in-progress\"];\n\nexport const Hint = React.forwardRef<\n HTMLElement,\n React.PropsWithChildren<HintProps>\n>(({ children, asChild, showOn = defaultShowOn, className, ...rest }, ref) => {\n const puzzleContext = useChessPuzzleContext();\n if (!puzzleContext) {\n throw new Error(\"PuzzleContext not found\");\n }\n const { onHint, status } = puzzleContext;\n\n const handleClick = React.useCallback(() => {\n onHint();\n }, [onHint]);\n\n if (!showOn.includes(status)) {\n return null;\n }\n\n return asChild ? (\n <Slot ref={ref} onClick={handleClick} className={className} {...rest}>\n {children}\n </Slot>\n ) : (\n <button\n ref={ref as React.RefObject<HTMLButtonElement>}\n type=\"button\"\n className={className}\n onClick={handleClick}\n {...rest}\n >\n {children}\n </button>\n );\n});\n\nHint.displayName = \"ChessPuzzle.Hint\";\n","import { Root } from \"./parts/Root\";\nimport { PuzzleBoard } from \"./parts/PuzzleBoard\";\nimport { Reset } from \"./parts/Reset\";\nimport { Hint } from \"./parts/Hint\";\n\nexport const ChessPuzzle = {\n Root,\n Board: PuzzleBoard,\n Reset,\n Hint,\n};\n"],"mappings":"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","names":["import_react","_","import_react_chess_game","puzzle","_a","import_react_chess_game","import_react","React","import_react","React","import_lodash","React","import_react","import_react_chess_game","React","import_react","React","import_react","import_react_slot","defaultShowOn","React"]}
package/dist/index.d.cts CHANGED
@@ -33,15 +33,23 @@ type Puzzle = {
33
33
  makeFirstMove?: boolean;
34
34
  };
35
35
 
36
- interface HintProps {
36
+ interface HintProps extends Omit<React__default.ButtonHTMLAttributes<HTMLButtonElement>, "onClick"> {
37
37
  asChild?: boolean;
38
+ /**
39
+ * The puzzle statuses in which the hint button should be visible.
40
+ * @default ["not-started", "in-progress"]
41
+ */
38
42
  showOn?: Status[];
39
43
  }
40
44
 
41
- interface ResetProps {
45
+ interface ResetProps extends Omit<React__default.ButtonHTMLAttributes<HTMLButtonElement>, "onReset"> {
42
46
  asChild?: boolean;
43
47
  puzzle?: Puzzle;
44
48
  onReset?: (puzzleContext: ChessPuzzleContextType) => void;
49
+ /**
50
+ * The puzzle statuses in which the reset button should be visible.
51
+ * @default ["failed", "solved"]
52
+ */
45
53
  showOn?: Status[];
46
54
  }
47
55
 
@@ -68,13 +76,19 @@ interface RootProps {
68
76
  onFail?: (puzzleContext: ChessPuzzleContextType) => void;
69
77
  /** Optional theme configuration. Supports partial themes - only override the colors you need. */
70
78
  theme?: PartialChessPuzzleTheme;
79
+ /** When true, any checkmate move solves the puzzle (not just the canonical solution). Defaults to true. */
80
+ solveOnCheckmate?: boolean;
71
81
  }
72
82
 
73
83
  declare const ChessPuzzle: {
74
84
  Root: React.FC<React.PropsWithChildren<RootProps>>;
75
- Board: React.FC<PuzzleBoardProps>;
76
- Reset: React.FC<React.PropsWithChildren<ResetProps>>;
77
- Hint: React.FC<React.PropsWithChildren<HintProps>>;
85
+ Board: React.ForwardRefExoticComponent<Omit<PuzzleBoardProps, "ref"> & React.RefAttributes<HTMLDivElement>>;
86
+ Reset: React.ForwardRefExoticComponent<ResetProps & {
87
+ children?: React.ReactNode | undefined;
88
+ } & React.RefAttributes<HTMLElement>>;
89
+ Hint: React.ForwardRefExoticComponent<HintProps & {
90
+ children?: React.ReactNode | undefined;
91
+ } & React.RefAttributes<HTMLElement>>;
78
92
  };
79
93
 
80
94
  declare const useChessPuzzleContext: () => ChessPuzzleContextType;