react-chess-puzzle-kit 1.0.6 → 1.0.8

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.
@@ -95,6 +95,8 @@ export interface PuzzleBoardWithControlsProps {
95
95
  /** Custom board/sidebar placement (overrides {@link analysisLayout} grid). */
96
96
  renderAnalysisMain?: (props: AnalysisMainRenderProps) => React.ReactNode;
97
97
  engine?: AnalysisEngineOptions;
98
+ /** Background multipv on the setup position for instant refutation (silent on puzzles). */
99
+ playTimeEngine?: AnalysisEngineOptions;
98
100
  /** After a clean solve (no wrong move, hint, or solution reveal), load the next card. */
99
101
  autoAdvanceOnComplete?: boolean;
100
102
  /** With {@link autoAdvanceOnComplete}, also advance after finishing following a miss or hint. */
@@ -117,4 +119,4 @@ export interface PuzzleBoardWithControlsProps {
117
119
  refutationEngine?: AnalysisEngineOptions;
118
120
  answerArrowColor?: string;
119
121
  }
120
- export declare const PuzzleBoardWithControls: ({ theme, boardTheme, apiProxy, renderControls, renderAnalysisSidebar, renderAnalysisContainer, renderEngineEvaluation, renderBoardCaption, renderBoardFeedback, puzzleBoardWidth, analysisLayout, analysisBoardWidth, renderAnalysisMain, engine, autoAdvanceOnComplete, autoAdvanceOnCompleteAfterIncorrect, autoAdvanceOnCompleteDelayMs, showCompletionRecap, revealAnswerOnIncorrect, showAnswerArrowOnIncorrect, allowRetryOnIncorrect, showRefutationOnIncorrect, autoShowWrongMoves, refutationEngine, answerArrowColor, }: PuzzleBoardWithControlsProps) => React.JSX.Element;
122
+ export declare const PuzzleBoardWithControls: ({ theme, boardTheme, apiProxy, renderControls, renderAnalysisSidebar, renderAnalysisContainer, renderEngineEvaluation, renderBoardCaption, renderBoardFeedback, puzzleBoardWidth, analysisLayout, analysisBoardWidth, renderAnalysisMain, engine, playTimeEngine, autoAdvanceOnComplete, autoAdvanceOnCompleteAfterIncorrect, autoAdvanceOnCompleteDelayMs, showCompletionRecap, revealAnswerOnIncorrect, showAnswerArrowOnIncorrect, allowRetryOnIncorrect, showRefutationOnIncorrect, autoShowWrongMoves, refutationEngine, answerArrowColor, }: PuzzleBoardWithControlsProps) => React.JSX.Element;
package/dist/index.esm.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { useState, useEffect, useRef, useMemo, useCallback } from 'react';
2
2
  import { jsx, jsxs } from 'react/jsx-runtime';
3
- import { useBoardRevision, useCorrectMoveFeedback, useIncorrectMoveFeedback, useMissBoard, HighlightChessboard, DEFAULT_ANSWER_ARROW_COLOR, uciFromDrop, fenAtPlyFromStart, useSolutionLineRecap, lastMoveUciAtPly, ThemeProvider, AnalysisErrorBoundary, AnalysisBoardCore, AnalysisBoardLayout, AnalysisBoard, BoardCompleteCheckOverlay, DEFAULT_ANALYSIS_LAYOUT, AUTO_ADVANCE_ON_COMPLETE_DELAY_MS, evaluateExpectedMoveDrop, fenAfterUci, boardSquareHighlightColors, analysisBoardHighlightColors } from 'react-chess-core';
3
+ import { useBoardRevision, useCorrectMoveFeedback, useIncorrectMoveFeedback, useMissBoard, HighlightChessboard, DEFAULT_ANSWER_ARROW_COLOR, uciFromDrop, fenAtPlyFromStart, useSolutionLineRecap, lastMoveUciAtPly, isAnalyzableFen, ThemeProvider, AnalysisErrorBoundary, AnalysisBoardCore, AnalysisBoardLayout, AnalysisBoard, PlayTimeEngineProvider, BoardCompleteCheckOverlay, DEFAULT_ANALYSIS_LAYOUT, AUTO_ADVANCE_ON_COMPLETE_DELAY_MS, evaluateExpectedMoveDrop, fenAfterUci, boardSquareHighlightColors, analysisBoardHighlightColors } from 'react-chess-core';
4
4
  export { DEFAULT_ANALYSIS_LAYOUT } from 'react-chess-core';
5
5
  import { Chess } from 'chess.js';
6
6
 
@@ -879,8 +879,8 @@ const buildCompletionRecapSource = (position, missedIndices) => {
879
879
  setupUci: startIndex > 0 ? (_b = movesUci[startIndex - 1]) !== null && _b !== void 0 ? _b : null : null,
880
880
  };
881
881
  };
882
- const PuzzleBoardWithControls = ({ theme, boardTheme, apiProxy, renderControls = defaultRenderControls, renderAnalysisSidebar, renderAnalysisContainer, renderEngineEvaluation, renderBoardCaption, renderBoardFeedback, puzzleBoardWidth = DEFAULT_PUZZLE_BOARD_WIDTH, analysisLayout = DEFAULT_ANALYSIS_LAYOUT, analysisBoardWidth, renderAnalysisMain, engine, autoAdvanceOnComplete = false, autoAdvanceOnCompleteAfterIncorrect = false, autoAdvanceOnCompleteDelayMs = AUTO_ADVANCE_ON_COMPLETE_DELAY_MS, showCompletionRecap = false, revealAnswerOnIncorrect = false, showAnswerArrowOnIncorrect = false, allowRetryOnIncorrect = true, showRefutationOnIncorrect, autoShowWrongMoves = true, refutationEngine, answerArrowColor, }) => {
883
- var _a, _b, _c, _d;
882
+ const PuzzleBoardWithControls = ({ theme, boardTheme, apiProxy, renderControls = defaultRenderControls, renderAnalysisSidebar, renderAnalysisContainer, renderEngineEvaluation, renderBoardCaption, renderBoardFeedback, puzzleBoardWidth = DEFAULT_PUZZLE_BOARD_WIDTH, analysisLayout = DEFAULT_ANALYSIS_LAYOUT, analysisBoardWidth, renderAnalysisMain, engine, playTimeEngine, autoAdvanceOnComplete = false, autoAdvanceOnCompleteAfterIncorrect = false, autoAdvanceOnCompleteDelayMs = AUTO_ADVANCE_ON_COMPLETE_DELAY_MS, showCompletionRecap = false, revealAnswerOnIncorrect = false, showAnswerArrowOnIncorrect = false, allowRetryOnIncorrect = true, showRefutationOnIncorrect, autoShowWrongMoves = true, refutationEngine, answerArrowColor, }) => {
883
+ var _a, _b, _c, _d, _e;
884
884
  const refutationOnIncorrect = showRefutationOnIncorrect !== null && showRefutationOnIncorrect !== void 0 ? showRefutationOnIncorrect : showAnswerArrowOnIncorrect;
885
885
  const stackControlsBelow = useStackPuzzleControlsBelow();
886
886
  const controlsPlacement = stackControlsBelow
@@ -1190,10 +1190,12 @@ const PuzzleBoardWithControls = ({ theme, boardTheme, apiProxy, renderControls =
1190
1190
  window.clearTimeout(timer);
1191
1191
  };
1192
1192
  }, [completionCheckVisible]);
1193
+ const analysis = usePuzzleAnalysis(position, resultStatus, puzzleNum);
1193
1194
  const shouldAutoAdvance = autoAdvanceOnComplete &&
1194
1195
  resultStatus === 'complete' &&
1195
1196
  !(hasIncorrectAttempt && !autoAdvanceOnCompleteAfterIncorrect) &&
1196
- (!showCompletionRecap || completionRecapDone);
1197
+ (!showCompletionRecap || completionRecapDone) &&
1198
+ !analysis.isOpen;
1197
1199
  const autoAdvance = usePuzzleAutoAdvanceCountdown(shouldAutoAdvance, autoAdvanceOnCompleteDelayMs, handleNextPuzzle);
1198
1200
  const controlState = {
1199
1201
  canShowHint: position !== null &&
@@ -1203,34 +1205,39 @@ const PuzzleBoardWithControls = ({ theme, boardTheme, apiProxy, renderControls =
1203
1205
  canShowSolution: position !== null &&
1204
1206
  (position.isSolutionRevealed() || !position.isFinished()),
1205
1207
  };
1206
- const analysis = usePuzzleAnalysis(position, resultStatus, puzzleNum);
1207
1208
  const analysisSnapshot = analysis.isOpen && analysis.snapshot ? analysis.snapshot : null;
1209
+ const setupFen = (_a = position === null || position === void 0 ? void 0 : position.fen()) !== null && _a !== void 0 ? _a : '';
1210
+ const playTimeEnabled = Boolean(position) &&
1211
+ !(position === null || position === void 0 ? void 0 : position.isFinished()) &&
1212
+ !analysisSnapshot &&
1213
+ isAnalyzableFen(setupFen);
1214
+ const resolvedPlayTimeEngine = useMemo(() => (Object.assign({ scriptUrl: engine === null || engine === void 0 ? void 0 : engine.scriptUrl }, playTimeEngine)), [engine === null || engine === void 0 ? void 0 : engine.scriptUrl, playTimeEngine]);
1208
1215
  const resolvedAnalysisBoardWidth = analysisBoardWidth !== null && analysisBoardWidth !== void 0 ? analysisBoardWidth : analysisLayout.boardWidth;
1209
1216
  const useHostAnalysisUi = Boolean(renderAnalysisSidebar &&
1210
1217
  renderAnalysisContainer &&
1211
1218
  (renderEngineEvaluation || (engine === null || engine === void 0 ? void 0 : engine.enabled) === false));
1212
- return (jsx(ThemeProvider, { theme: theme, boardTheme: boardTheme, children: analysisSnapshot ? (jsx(AnalysisErrorBoundary, { onClose: analysis.closeAnalysis, children: useHostAnalysisUi ? (jsx(AnalysisBoardCore, { analysisContext: analysisSnapshot, onClose: analysis.closeAnalysis, theme: theme, boardWidth: resolvedAnalysisBoardWidth, engine: engine, renderMain: renderAnalysisMain !== null && renderAnalysisMain !== void 0 ? renderAnalysisMain : (({ board, sidebar, model }) => (jsx(AnalysisBoardLayout, { layout: analysisLayout, model: model, board: board, sidebar: sidebar }))), renderSidebar: renderAnalysisSidebar, renderContainer: renderAnalysisContainer, renderEngineEvaluation: renderEngineEvaluation !== null && renderEngineEvaluation !== void 0 ? renderEngineEvaluation : (() => null) })) : (jsx(AnalysisBoard, { analysisContext: analysisSnapshot, onClose: analysis.closeAnalysis, theme: theme, layout: analysisLayout, engine: engine, renderMain: renderAnalysisMain, renderSidebar: renderAnalysisSidebar, renderContainer: renderAnalysisContainer, renderEngineEvaluation: renderEngineEvaluation })) })) : (jsxs("div", { style: puzzlePlayRowStyle(controlsPlacement), children: [jsxs("div", { style: puzzleBoardColumnStyle(puzzleBoardWidth, controlsPlacement), children: [jsxs("div", { style: puzzleBoardSlotWrapperStyle(), children: [jsx("div", { style: puzzleBoardSlotStyle(), children: jsx(PuzzlePlaySurface, { position: position, boardWidth: puzzleBoardWidth, onFeedback: handleFeedback, incInteractionNum: incInteractionNum, onResumeCorrect: runResumeAutoAdvance, revealAnswerOnIncorrect: revealAnswerOnIncorrect, showAnswerArrowOnIncorrect: showAnswerArrowOnIncorrect, allowRetryOnIncorrect: allowRetryOnIncorrect, showRefutationOnIncorrect: refutationOnIncorrect, autoShowWrongMoves: autoShowWrongMoves, refutationEngine: refutationEngine !== null && refutationEngine !== void 0 ? refutationEngine : engine, answerArrowColor: answerArrowColor, positionLocked: loadingNextPuzzle ||
1213
- completionCheckVisible ||
1214
- isCompletionRecapping, onMissFeedbackChange: setMissFeedback, recapBoard: isCompletionRecapping
1215
- ? {
1216
- fen: completionRecap.fen,
1217
- lastMoveUci: completionRecap.lastMoveUci,
1218
- customArrows: completionRecap.customArrows,
1219
- animationDuration: completionRecap.animationDuration,
1220
- }
1221
- : null }) }), completionCheckVisible && (jsx(BoardCompleteCheckOverlay, { variant: hasIncorrectAttempt || completedAfterMiss || hintUsed
1219
+ return (jsx(ThemeProvider, { theme: theme, boardTheme: boardTheme, children: analysisSnapshot ? (jsx(AnalysisErrorBoundary, { onClose: analysis.closeAnalysis, children: useHostAnalysisUi ? (jsx(AnalysisBoardCore, { analysisContext: analysisSnapshot, onClose: analysis.closeAnalysis, theme: theme, boardWidth: resolvedAnalysisBoardWidth, engine: engine, renderMain: renderAnalysisMain !== null && renderAnalysisMain !== void 0 ? renderAnalysisMain : (({ board, sidebar, model }) => (jsx(AnalysisBoardLayout, { layout: analysisLayout, model: model, board: board, sidebar: sidebar }))), renderSidebar: renderAnalysisSidebar, renderContainer: renderAnalysisContainer, renderEngineEvaluation: renderEngineEvaluation !== null && renderEngineEvaluation !== void 0 ? renderEngineEvaluation : (() => null) })) : (jsx(AnalysisBoard, { analysisContext: analysisSnapshot, onClose: analysis.closeAnalysis, theme: theme, layout: analysisLayout, engine: engine, renderMain: renderAnalysisMain, renderSidebar: renderAnalysisSidebar, renderContainer: renderAnalysisContainer, renderEngineEvaluation: renderEngineEvaluation })) })) : (jsxs("div", { style: puzzlePlayRowStyle(controlsPlacement), children: [jsxs("div", { style: puzzleBoardColumnStyle(puzzleBoardWidth, controlsPlacement), children: [jsxs("div", { style: puzzleBoardSlotWrapperStyle(), children: [jsx("div", { style: puzzleBoardSlotStyle(), children: jsx(PlayTimeEngineProvider, { fen: setupFen, enabled: playTimeEnabled, options: resolvedPlayTimeEngine, children: jsx(PuzzlePlaySurface, { position: position, boardWidth: puzzleBoardWidth, onFeedback: handleFeedback, incInteractionNum: incInteractionNum, onResumeCorrect: runResumeAutoAdvance, revealAnswerOnIncorrect: revealAnswerOnIncorrect, showAnswerArrowOnIncorrect: showAnswerArrowOnIncorrect, allowRetryOnIncorrect: allowRetryOnIncorrect, showRefutationOnIncorrect: refutationOnIncorrect, autoShowWrongMoves: autoShowWrongMoves, refutationEngine: refutationEngine !== null && refutationEngine !== void 0 ? refutationEngine : engine, answerArrowColor: answerArrowColor, positionLocked: loadingNextPuzzle ||
1220
+ completionCheckVisible ||
1221
+ isCompletionRecapping, onMissFeedbackChange: setMissFeedback, recapBoard: isCompletionRecapping
1222
+ ? {
1223
+ fen: completionRecap.fen,
1224
+ lastMoveUci: completionRecap.lastMoveUci,
1225
+ customArrows: completionRecap.customArrows,
1226
+ animationDuration: completionRecap.animationDuration,
1227
+ }
1228
+ : null }) }) }), completionCheckVisible && (jsx(BoardCompleteCheckOverlay, { variant: hasIncorrectAttempt || completedAfterMiss || hintUsed
1222
1229
  ? 'partial'
1223
1230
  : 'success' }))] }), renderBoardCaption && (jsx("div", { style: puzzleBoardCaptionSlotStyle(), children: renderBoardCaption({
1224
- sideToMove: (_a = position === null || position === void 0 ? void 0 : position.getSideToMove()) !== null && _a !== void 0 ? _a : null,
1231
+ sideToMove: (_b = position === null || position === void 0 ? void 0 : position.getSideToMove()) !== null && _b !== void 0 ? _b : null,
1225
1232
  playerColor: position
1226
1233
  ? position.getPlayerColor()
1227
1234
  : null,
1228
1235
  incorrectAttempt: resultStatus === 'incorrect',
1229
1236
  complete: resultStatus === 'complete',
1230
1237
  cleanSolve: !hasIncorrectAttempt,
1231
- refutationSan: (_b = missFeedback === null || missFeedback === void 0 ? void 0 : missFeedback.refutationSan) !== null && _b !== void 0 ? _b : null,
1232
- missPhase: (_c = missFeedback === null || missFeedback === void 0 ? void 0 : missFeedback.phase) !== null && _c !== void 0 ? _c : null,
1233
- answerArrowVisible: (_d = missFeedback === null || missFeedback === void 0 ? void 0 : missFeedback.answerArrowVisible) !== null && _d !== void 0 ? _d : false,
1238
+ refutationSan: (_c = missFeedback === null || missFeedback === void 0 ? void 0 : missFeedback.refutationSan) !== null && _c !== void 0 ? _c : null,
1239
+ missPhase: (_d = missFeedback === null || missFeedback === void 0 ? void 0 : missFeedback.phase) !== null && _d !== void 0 ? _d : null,
1240
+ answerArrowVisible: (_e = missFeedback === null || missFeedback === void 0 ? void 0 : missFeedback.answerArrowVisible) !== null && _e !== void 0 ? _e : false,
1234
1241
  completedAfterMiss,
1235
1242
  hintUsed,
1236
1243
  }) }))] }), jsxs("div", { style: puzzleControlsSlotStyle(controlsPlacement), children: [renderControls(handleHintRequest, handleShowSolution, handleNextPuzzle, resultStatus, {
package/dist/index.js CHANGED
@@ -880,8 +880,8 @@ const buildCompletionRecapSource = (position, missedIndices) => {
880
880
  setupUci: startIndex > 0 ? (_b = movesUci[startIndex - 1]) !== null && _b !== void 0 ? _b : null : null,
881
881
  };
882
882
  };
883
- const PuzzleBoardWithControls = ({ theme, boardTheme, apiProxy, renderControls = defaultRenderControls, renderAnalysisSidebar, renderAnalysisContainer, renderEngineEvaluation, renderBoardCaption, renderBoardFeedback, puzzleBoardWidth = DEFAULT_PUZZLE_BOARD_WIDTH, analysisLayout = reactChessCore.DEFAULT_ANALYSIS_LAYOUT, analysisBoardWidth, renderAnalysisMain, engine, autoAdvanceOnComplete = false, autoAdvanceOnCompleteAfterIncorrect = false, autoAdvanceOnCompleteDelayMs = reactChessCore.AUTO_ADVANCE_ON_COMPLETE_DELAY_MS, showCompletionRecap = false, revealAnswerOnIncorrect = false, showAnswerArrowOnIncorrect = false, allowRetryOnIncorrect = true, showRefutationOnIncorrect, autoShowWrongMoves = true, refutationEngine, answerArrowColor, }) => {
884
- var _a, _b, _c, _d;
883
+ const PuzzleBoardWithControls = ({ theme, boardTheme, apiProxy, renderControls = defaultRenderControls, renderAnalysisSidebar, renderAnalysisContainer, renderEngineEvaluation, renderBoardCaption, renderBoardFeedback, puzzleBoardWidth = DEFAULT_PUZZLE_BOARD_WIDTH, analysisLayout = reactChessCore.DEFAULT_ANALYSIS_LAYOUT, analysisBoardWidth, renderAnalysisMain, engine, playTimeEngine, autoAdvanceOnComplete = false, autoAdvanceOnCompleteAfterIncorrect = false, autoAdvanceOnCompleteDelayMs = reactChessCore.AUTO_ADVANCE_ON_COMPLETE_DELAY_MS, showCompletionRecap = false, revealAnswerOnIncorrect = false, showAnswerArrowOnIncorrect = false, allowRetryOnIncorrect = true, showRefutationOnIncorrect, autoShowWrongMoves = true, refutationEngine, answerArrowColor, }) => {
884
+ var _a, _b, _c, _d, _e;
885
885
  const refutationOnIncorrect = showRefutationOnIncorrect !== null && showRefutationOnIncorrect !== void 0 ? showRefutationOnIncorrect : showAnswerArrowOnIncorrect;
886
886
  const stackControlsBelow = useStackPuzzleControlsBelow();
887
887
  const controlsPlacement = stackControlsBelow
@@ -1191,10 +1191,12 @@ const PuzzleBoardWithControls = ({ theme, boardTheme, apiProxy, renderControls =
1191
1191
  window.clearTimeout(timer);
1192
1192
  };
1193
1193
  }, [completionCheckVisible]);
1194
+ const analysis = usePuzzleAnalysis(position, resultStatus, puzzleNum);
1194
1195
  const shouldAutoAdvance = autoAdvanceOnComplete &&
1195
1196
  resultStatus === 'complete' &&
1196
1197
  !(hasIncorrectAttempt && !autoAdvanceOnCompleteAfterIncorrect) &&
1197
- (!showCompletionRecap || completionRecapDone);
1198
+ (!showCompletionRecap || completionRecapDone) &&
1199
+ !analysis.isOpen;
1198
1200
  const autoAdvance = usePuzzleAutoAdvanceCountdown(shouldAutoAdvance, autoAdvanceOnCompleteDelayMs, handleNextPuzzle);
1199
1201
  const controlState = {
1200
1202
  canShowHint: position !== null &&
@@ -1204,34 +1206,39 @@ const PuzzleBoardWithControls = ({ theme, boardTheme, apiProxy, renderControls =
1204
1206
  canShowSolution: position !== null &&
1205
1207
  (position.isSolutionRevealed() || !position.isFinished()),
1206
1208
  };
1207
- const analysis = usePuzzleAnalysis(position, resultStatus, puzzleNum);
1208
1209
  const analysisSnapshot = analysis.isOpen && analysis.snapshot ? analysis.snapshot : null;
1210
+ const setupFen = (_a = position === null || position === void 0 ? void 0 : position.fen()) !== null && _a !== void 0 ? _a : '';
1211
+ const playTimeEnabled = Boolean(position) &&
1212
+ !(position === null || position === void 0 ? void 0 : position.isFinished()) &&
1213
+ !analysisSnapshot &&
1214
+ reactChessCore.isAnalyzableFen(setupFen);
1215
+ const resolvedPlayTimeEngine = react.useMemo(() => (Object.assign({ scriptUrl: engine === null || engine === void 0 ? void 0 : engine.scriptUrl }, playTimeEngine)), [engine === null || engine === void 0 ? void 0 : engine.scriptUrl, playTimeEngine]);
1209
1216
  const resolvedAnalysisBoardWidth = analysisBoardWidth !== null && analysisBoardWidth !== void 0 ? analysisBoardWidth : analysisLayout.boardWidth;
1210
1217
  const useHostAnalysisUi = Boolean(renderAnalysisSidebar &&
1211
1218
  renderAnalysisContainer &&
1212
1219
  (renderEngineEvaluation || (engine === null || engine === void 0 ? void 0 : engine.enabled) === false));
1213
- return (jsxRuntime.jsx(reactChessCore.ThemeProvider, { theme: theme, boardTheme: boardTheme, children: analysisSnapshot ? (jsxRuntime.jsx(reactChessCore.AnalysisErrorBoundary, { onClose: analysis.closeAnalysis, children: useHostAnalysisUi ? (jsxRuntime.jsx(reactChessCore.AnalysisBoardCore, { analysisContext: analysisSnapshot, onClose: analysis.closeAnalysis, theme: theme, boardWidth: resolvedAnalysisBoardWidth, engine: engine, renderMain: renderAnalysisMain !== null && renderAnalysisMain !== void 0 ? renderAnalysisMain : (({ board, sidebar, model }) => (jsxRuntime.jsx(reactChessCore.AnalysisBoardLayout, { layout: analysisLayout, model: model, board: board, sidebar: sidebar }))), renderSidebar: renderAnalysisSidebar, renderContainer: renderAnalysisContainer, renderEngineEvaluation: renderEngineEvaluation !== null && renderEngineEvaluation !== void 0 ? renderEngineEvaluation : (() => null) })) : (jsxRuntime.jsx(reactChessCore.AnalysisBoard, { analysisContext: analysisSnapshot, onClose: analysis.closeAnalysis, theme: theme, layout: analysisLayout, engine: engine, renderMain: renderAnalysisMain, renderSidebar: renderAnalysisSidebar, renderContainer: renderAnalysisContainer, renderEngineEvaluation: renderEngineEvaluation })) })) : (jsxRuntime.jsxs("div", { style: puzzlePlayRowStyle(controlsPlacement), children: [jsxRuntime.jsxs("div", { style: puzzleBoardColumnStyle(puzzleBoardWidth, controlsPlacement), children: [jsxRuntime.jsxs("div", { style: puzzleBoardSlotWrapperStyle(), children: [jsxRuntime.jsx("div", { style: puzzleBoardSlotStyle(), children: jsxRuntime.jsx(PuzzlePlaySurface, { position: position, boardWidth: puzzleBoardWidth, onFeedback: handleFeedback, incInteractionNum: incInteractionNum, onResumeCorrect: runResumeAutoAdvance, revealAnswerOnIncorrect: revealAnswerOnIncorrect, showAnswerArrowOnIncorrect: showAnswerArrowOnIncorrect, allowRetryOnIncorrect: allowRetryOnIncorrect, showRefutationOnIncorrect: refutationOnIncorrect, autoShowWrongMoves: autoShowWrongMoves, refutationEngine: refutationEngine !== null && refutationEngine !== void 0 ? refutationEngine : engine, answerArrowColor: answerArrowColor, positionLocked: loadingNextPuzzle ||
1214
- completionCheckVisible ||
1215
- isCompletionRecapping, onMissFeedbackChange: setMissFeedback, recapBoard: isCompletionRecapping
1216
- ? {
1217
- fen: completionRecap.fen,
1218
- lastMoveUci: completionRecap.lastMoveUci,
1219
- customArrows: completionRecap.customArrows,
1220
- animationDuration: completionRecap.animationDuration,
1221
- }
1222
- : null }) }), completionCheckVisible && (jsxRuntime.jsx(reactChessCore.BoardCompleteCheckOverlay, { variant: hasIncorrectAttempt || completedAfterMiss || hintUsed
1220
+ return (jsxRuntime.jsx(reactChessCore.ThemeProvider, { theme: theme, boardTheme: boardTheme, children: analysisSnapshot ? (jsxRuntime.jsx(reactChessCore.AnalysisErrorBoundary, { onClose: analysis.closeAnalysis, children: useHostAnalysisUi ? (jsxRuntime.jsx(reactChessCore.AnalysisBoardCore, { analysisContext: analysisSnapshot, onClose: analysis.closeAnalysis, theme: theme, boardWidth: resolvedAnalysisBoardWidth, engine: engine, renderMain: renderAnalysisMain !== null && renderAnalysisMain !== void 0 ? renderAnalysisMain : (({ board, sidebar, model }) => (jsxRuntime.jsx(reactChessCore.AnalysisBoardLayout, { layout: analysisLayout, model: model, board: board, sidebar: sidebar }))), renderSidebar: renderAnalysisSidebar, renderContainer: renderAnalysisContainer, renderEngineEvaluation: renderEngineEvaluation !== null && renderEngineEvaluation !== void 0 ? renderEngineEvaluation : (() => null) })) : (jsxRuntime.jsx(reactChessCore.AnalysisBoard, { analysisContext: analysisSnapshot, onClose: analysis.closeAnalysis, theme: theme, layout: analysisLayout, engine: engine, renderMain: renderAnalysisMain, renderSidebar: renderAnalysisSidebar, renderContainer: renderAnalysisContainer, renderEngineEvaluation: renderEngineEvaluation })) })) : (jsxRuntime.jsxs("div", { style: puzzlePlayRowStyle(controlsPlacement), children: [jsxRuntime.jsxs("div", { style: puzzleBoardColumnStyle(puzzleBoardWidth, controlsPlacement), children: [jsxRuntime.jsxs("div", { style: puzzleBoardSlotWrapperStyle(), children: [jsxRuntime.jsx("div", { style: puzzleBoardSlotStyle(), children: jsxRuntime.jsx(reactChessCore.PlayTimeEngineProvider, { fen: setupFen, enabled: playTimeEnabled, options: resolvedPlayTimeEngine, children: jsxRuntime.jsx(PuzzlePlaySurface, { position: position, boardWidth: puzzleBoardWidth, onFeedback: handleFeedback, incInteractionNum: incInteractionNum, onResumeCorrect: runResumeAutoAdvance, revealAnswerOnIncorrect: revealAnswerOnIncorrect, showAnswerArrowOnIncorrect: showAnswerArrowOnIncorrect, allowRetryOnIncorrect: allowRetryOnIncorrect, showRefutationOnIncorrect: refutationOnIncorrect, autoShowWrongMoves: autoShowWrongMoves, refutationEngine: refutationEngine !== null && refutationEngine !== void 0 ? refutationEngine : engine, answerArrowColor: answerArrowColor, positionLocked: loadingNextPuzzle ||
1221
+ completionCheckVisible ||
1222
+ isCompletionRecapping, onMissFeedbackChange: setMissFeedback, recapBoard: isCompletionRecapping
1223
+ ? {
1224
+ fen: completionRecap.fen,
1225
+ lastMoveUci: completionRecap.lastMoveUci,
1226
+ customArrows: completionRecap.customArrows,
1227
+ animationDuration: completionRecap.animationDuration,
1228
+ }
1229
+ : null }) }) }), completionCheckVisible && (jsxRuntime.jsx(reactChessCore.BoardCompleteCheckOverlay, { variant: hasIncorrectAttempt || completedAfterMiss || hintUsed
1223
1230
  ? 'partial'
1224
1231
  : 'success' }))] }), renderBoardCaption && (jsxRuntime.jsx("div", { style: puzzleBoardCaptionSlotStyle(), children: renderBoardCaption({
1225
- sideToMove: (_a = position === null || position === void 0 ? void 0 : position.getSideToMove()) !== null && _a !== void 0 ? _a : null,
1232
+ sideToMove: (_b = position === null || position === void 0 ? void 0 : position.getSideToMove()) !== null && _b !== void 0 ? _b : null,
1226
1233
  playerColor: position
1227
1234
  ? position.getPlayerColor()
1228
1235
  : null,
1229
1236
  incorrectAttempt: resultStatus === 'incorrect',
1230
1237
  complete: resultStatus === 'complete',
1231
1238
  cleanSolve: !hasIncorrectAttempt,
1232
- refutationSan: (_b = missFeedback === null || missFeedback === void 0 ? void 0 : missFeedback.refutationSan) !== null && _b !== void 0 ? _b : null,
1233
- missPhase: (_c = missFeedback === null || missFeedback === void 0 ? void 0 : missFeedback.phase) !== null && _c !== void 0 ? _c : null,
1234
- answerArrowVisible: (_d = missFeedback === null || missFeedback === void 0 ? void 0 : missFeedback.answerArrowVisible) !== null && _d !== void 0 ? _d : false,
1239
+ refutationSan: (_c = missFeedback === null || missFeedback === void 0 ? void 0 : missFeedback.refutationSan) !== null && _c !== void 0 ? _c : null,
1240
+ missPhase: (_d = missFeedback === null || missFeedback === void 0 ? void 0 : missFeedback.phase) !== null && _d !== void 0 ? _d : null,
1241
+ answerArrowVisible: (_e = missFeedback === null || missFeedback === void 0 ? void 0 : missFeedback.answerArrowVisible) !== null && _e !== void 0 ? _e : false,
1235
1242
  completedAfterMiss,
1236
1243
  hintUsed,
1237
1244
  }) }))] }), jsxRuntime.jsxs("div", { style: puzzleControlsSlotStyle(controlsPlacement), children: [renderControls(handleHintRequest, handleShowSolution, handleNextPuzzle, resultStatus, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-chess-puzzle-kit",
3
- "version": "1.0.6",
3
+ "version": "1.0.8",
4
4
  "description": "React chess puzzle kit: play, controls, analysis, and browser Stockfish for endchess.training and other apps",
5
5
  "license": "MIT",
6
6
  "author": "Robert Blackwell",
@@ -68,11 +68,13 @@
68
68
  "@storybook/react": "^8.2.9",
69
69
  "@storybook/react-vite": "^8.2.9",
70
70
  "@storybook/test": "^8.2.9",
71
+ "@testing-library/react": "^16.0.1",
71
72
  "@types/jest": "^29.5.12",
72
73
  "@types/react": "^18.3.12",
73
74
  "@types/react-dom": "^18.3.1",
74
75
  "chess.js": "^1.0.0-beta.8",
75
76
  "jest": "^29.7.0",
77
+ "jest-environment-jsdom": "^29.7.0",
76
78
  "react": "^18.3.1",
77
79
  "react-chess-core": "^0.1.8",
78
80
  "react-chessboard": "^4.7.1",