react-chess-puzzle-kit 1.0.7 → 1.0.9
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.
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { type BoardThemeId } from 'react-chess-core';
|
|
2
|
+
import { type AnalysisEngineOptions, type BoardThemeId } from 'react-chess-core';
|
|
3
3
|
export type LineTrainSide = 'w' | 'b';
|
|
4
4
|
/** A line to drill: a start position plus the moves to walk, from one side. */
|
|
5
5
|
export interface LineSpec {
|
|
@@ -38,6 +38,12 @@ export interface LineBoardWithControlsProps {
|
|
|
38
38
|
onMove?: (feedback: LineMoveFeedback) => void;
|
|
39
39
|
/** Omit to use {@link defaultRenderLineControls}. */
|
|
40
40
|
renderControls?: (props: LineControlsRenderProps) => React.ReactNode;
|
|
41
|
+
/** Optional content above the board (e.g. eval bar), inside play-time engine context. */
|
|
42
|
+
renderAboveBoard?: (props: {
|
|
43
|
+
fen: string;
|
|
44
|
+
}) => React.ReactNode;
|
|
45
|
+
/** Stockfish options when {@link renderAboveBoard} is set. */
|
|
46
|
+
playTimeEngine?: AnalysisEngineOptions;
|
|
41
47
|
boardWidth?: number;
|
|
42
48
|
/** Delay before auto-playing each opponent move (ms). */
|
|
43
49
|
opponentMoveDelayMs?: number;
|
|
@@ -49,4 +55,4 @@ export interface LineBoardWithControlsProps {
|
|
|
49
55
|
* tactical puzzles. Mount one instance per drill (key it by line) so its
|
|
50
56
|
* internal state resets between lines.
|
|
51
57
|
*/
|
|
52
|
-
export declare const LineBoardWithControls: ({ theme, boardTheme, line, onComplete, onMove, renderControls, boardWidth, opponentMoveDelayMs, }: LineBoardWithControlsProps) => React.JSX.Element;
|
|
58
|
+
export declare const LineBoardWithControls: ({ theme, boardTheme, line, onComplete, onMove, renderControls, renderAboveBoard, playTimeEngine, boardWidth, opponentMoveDelayMs, }: LineBoardWithControlsProps) => React.JSX.Element;
|
|
@@ -82,6 +82,10 @@ export interface PuzzleBoardWithControlsProps {
|
|
|
82
82
|
renderAnalysisSidebar?: (props: AnalysisSidebarRenderProps) => React.ReactNode;
|
|
83
83
|
renderAnalysisContainer?: (props: AnalysisContainerRenderProps) => React.ReactNode;
|
|
84
84
|
renderEngineEvaluation?: (props: EngineEvaluationRenderProps) => React.ReactNode;
|
|
85
|
+
/** Optional content above the board (e.g. eval bar), inside play-time engine context. */
|
|
86
|
+
renderAboveBoard?: (props: {
|
|
87
|
+
fen: string;
|
|
88
|
+
}) => React.ReactNode;
|
|
85
89
|
/** Optional label below the board (e.g. side to move). */
|
|
86
90
|
renderBoardCaption?: (props: BoardCaptionRenderProps) => React.ReactNode;
|
|
87
91
|
/** Optional result feedback shown at the bottom of the controls column. */
|
|
@@ -95,6 +99,8 @@ export interface PuzzleBoardWithControlsProps {
|
|
|
95
99
|
/** Custom board/sidebar placement (overrides {@link analysisLayout} grid). */
|
|
96
100
|
renderAnalysisMain?: (props: AnalysisMainRenderProps) => React.ReactNode;
|
|
97
101
|
engine?: AnalysisEngineOptions;
|
|
102
|
+
/** Background multipv on the setup position for instant refutation (silent on puzzles). */
|
|
103
|
+
playTimeEngine?: AnalysisEngineOptions;
|
|
98
104
|
/** After a clean solve (no wrong move, hint, or solution reveal), load the next card. */
|
|
99
105
|
autoAdvanceOnComplete?: boolean;
|
|
100
106
|
/** With {@link autoAdvanceOnComplete}, also advance after finishing following a miss or hint. */
|
|
@@ -117,4 +123,4 @@ export interface PuzzleBoardWithControlsProps {
|
|
|
117
123
|
refutationEngine?: AnalysisEngineOptions;
|
|
118
124
|
answerArrowColor?: string;
|
|
119
125
|
}
|
|
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;
|
|
126
|
+
export declare const PuzzleBoardWithControls: ({ theme, boardTheme, apiProxy, renderControls, renderAnalysisSidebar, renderAnalysisContainer, renderEngineEvaluation, renderAboveBoard, 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
|
-
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';
|
|
2
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
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
|
|
|
@@ -61,7 +61,7 @@ const EMPTY_BOARD_FEN = '8/8/8/8/8/8/8/8 w - - 0 1';
|
|
|
61
61
|
* visible while the next position loads so layout and perspective do not flicker.
|
|
62
62
|
*/
|
|
63
63
|
const PuzzlePlaySurface = ({ position, onFeedback, incInteractionNum, boardWidth, onResumeCorrect, revealAnswerOnIncorrect = false, showAnswerArrowOnIncorrect = false, allowRetryOnIncorrect = true, showRefutationOnIncorrect = false, autoShowWrongMoves = true, refutationEngine, answerArrowColor = DEFAULT_ANSWER_ARROW_COLOR, positionLocked = false, onMissFeedbackChange, recapBoard = null, }) => {
|
|
64
|
-
var _a, _b, _c, _d, _e
|
|
64
|
+
var _a, _b, _c, _d, _e;
|
|
65
65
|
const [showAnswerArrow, setShowAnswerArrow] = useState(false);
|
|
66
66
|
const [incorrectActive, setIncorrectActive] = useState(false);
|
|
67
67
|
const attemptMissedRef = useRef(false);
|
|
@@ -98,16 +98,14 @@ const PuzzlePlaySurface = ({ position, onFeedback, incInteractionNum, boardWidth
|
|
|
98
98
|
autoShowWrongMoves: useRefutation ? true : autoShowWrongMoves,
|
|
99
99
|
engineOptions: refutationEngine,
|
|
100
100
|
});
|
|
101
|
-
const missPhase =
|
|
101
|
+
const missPhase = missBoard.phase;
|
|
102
102
|
const answerArrowVisible = useRefutation
|
|
103
103
|
? incorrectActive && missPhase === 'answer'
|
|
104
104
|
: showAnswerArrow;
|
|
105
|
-
const overlayIncorrectSquare =
|
|
106
|
-
? missBoard.
|
|
107
|
-
:
|
|
108
|
-
const refutationMoveSquare = useRefutation && incorrectActive
|
|
109
|
-
? missBoard.missSequence.display.refutationMoveSquare
|
|
110
|
-
: null;
|
|
105
|
+
const overlayIncorrectSquare = useRefutation && incorrectActive
|
|
106
|
+
? missBoard.incorrectMoveSquare
|
|
107
|
+
: transientIncorrectSquare;
|
|
108
|
+
const refutationMoveSquare = useRefutation && incorrectActive ? missBoard.refutationMoveSquare : null;
|
|
111
109
|
useEffect(() => {
|
|
112
110
|
setShowAnswerArrow(false);
|
|
113
111
|
setIncorrectActive(false);
|
|
@@ -122,14 +120,13 @@ const PuzzlePlaySurface = ({ position, onFeedback, incInteractionNum, boardWidth
|
|
|
122
120
|
position,
|
|
123
121
|
]);
|
|
124
122
|
useEffect(() => {
|
|
125
|
-
var _a, _b;
|
|
126
123
|
if (!onMissFeedbackChange) {
|
|
127
124
|
return;
|
|
128
125
|
}
|
|
129
126
|
if (useRefutation && incorrectActive) {
|
|
130
127
|
onMissFeedbackChange({
|
|
131
128
|
refutationSan: missBoard.refutation.refutationSan,
|
|
132
|
-
phase:
|
|
129
|
+
phase: missBoard.phase,
|
|
133
130
|
answerArrowVisible,
|
|
134
131
|
});
|
|
135
132
|
return;
|
|
@@ -146,7 +143,7 @@ const PuzzlePlaySurface = ({ position, onFeedback, incInteractionNum, boardWidth
|
|
|
146
143
|
}, [
|
|
147
144
|
answerArrowVisible,
|
|
148
145
|
incorrectActive,
|
|
149
|
-
|
|
146
|
+
missBoard.phase,
|
|
150
147
|
missBoard.refutation.refutationSan,
|
|
151
148
|
onMissFeedbackChange,
|
|
152
149
|
showAnswerArrow,
|
|
@@ -186,12 +183,8 @@ const PuzzlePlaySurface = ({ position, onFeedback, incInteractionNum, boardWidth
|
|
|
186
183
|
? recapBoard.lastMoveUci
|
|
187
184
|
: useRefutation && incorrectActive
|
|
188
185
|
? missBoard.lastMoveUci
|
|
189
|
-
: ((
|
|
190
|
-
const missLocked = useRefutation &&
|
|
191
|
-
incorrectActive &&
|
|
192
|
-
(missBoard.boardAnimating ||
|
|
193
|
-
missPhase === 'wrong' ||
|
|
194
|
-
missPhase === 'refutation');
|
|
186
|
+
: ((_c = position === null || position === void 0 ? void 0 : position.getLastMoveUci()) !== null && _c !== void 0 ? _c : null);
|
|
187
|
+
const missLocked = useRefutation && incorrectActive && missBoard.inputLocked;
|
|
195
188
|
const arePiecesDraggable = !isRecapping &&
|
|
196
189
|
position !== null &&
|
|
197
190
|
!positionLocked &&
|
|
@@ -221,7 +214,9 @@ const PuzzlePlaySurface = ({ position, onFeedback, incInteractionNum, boardWidth
|
|
|
221
214
|
});
|
|
222
215
|
if (!guess.accepted) {
|
|
223
216
|
attemptMissedRef.current = true;
|
|
224
|
-
|
|
217
|
+
if (!useRefutation) {
|
|
218
|
+
showIncorrectMove(sourceSquare);
|
|
219
|
+
}
|
|
225
220
|
onFeedback({
|
|
226
221
|
index: position.getIndex(),
|
|
227
222
|
guess: { sourceSquare, targetSquare, piece },
|
|
@@ -301,7 +296,11 @@ const PuzzlePlaySurface = ({ position, onFeedback, incInteractionNum, boardWidth
|
|
|
301
296
|
showCorrectMove(targetSquare, finishCorrectFeedback);
|
|
302
297
|
return true;
|
|
303
298
|
};
|
|
304
|
-
return hasBoard ? (jsx(HighlightChessboard, { boardWidth: boardWidth, checkSquare: isRecapping ? '' : ((
|
|
299
|
+
return hasBoard ? (jsx(HighlightChessboard, { boardWidth: boardWidth, checkSquare: isRecapping ? '' : ((_d = position === null || position === void 0 ? void 0 : position.getCheckSquare()) !== null && _d !== void 0 ? _d : ''), hintSquare: isRecapping ? null : ((_e = position === null || position === void 0 ? void 0 : position.getHintSquare()) !== null && _e !== void 0 ? _e : null), incorrectMoveSquare: isRecapping ? null : overlayIncorrectSquare, refutationMoveSquare: isRecapping ? null : refutationMoveSquare, correctMoveSquare: isRecapping ? null : correctMoveSquare, customArrows: customArrows, lastMoveUci: lastMoveUci, onPieceDrop: onPieceDrop, position: displayFen, boardOrientation: boardOrientation, arePiecesDraggable: arePiecesDraggable, areArrowsAllowed: false, promotionDialogVariant: "modal", animationDuration: isRecapping
|
|
300
|
+
? recapBoard.animationDuration
|
|
301
|
+
: useRefutation && incorrectActive
|
|
302
|
+
? missBoard.animationDuration
|
|
303
|
+
: 0 }, revision)) : null;
|
|
305
304
|
};
|
|
306
305
|
|
|
307
306
|
const PuzzleBoard = ({ position, onFeedback, incInteractionNum, boardWidth, revealAnswerOnIncorrect = false, showAnswerArrowOnIncorrect = false, allowRetryOnIncorrect = true, answerArrowColor, }) => (jsx(PuzzlePlaySurface, { position: position, onFeedback: onFeedback, incInteractionNum: incInteractionNum, boardWidth: boardWidth, revealAnswerOnIncorrect: revealAnswerOnIncorrect, showAnswerArrowOnIncorrect: showAnswerArrowOnIncorrect, allowRetryOnIncorrect: allowRetryOnIncorrect, answerArrowColor: answerArrowColor }));
|
|
@@ -370,6 +369,7 @@ const usePuzzleCompletionRecap = ({ source, active, onComplete, }) => {
|
|
|
370
369
|
segmentStartFen: startFen,
|
|
371
370
|
setupUci,
|
|
372
371
|
onComplete,
|
|
372
|
+
completeImmediatelyWhenNoMisses: true,
|
|
373
373
|
resolveFen,
|
|
374
374
|
});
|
|
375
375
|
};
|
|
@@ -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, renderAboveBoard, 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
|
|
@@ -1176,8 +1176,12 @@ const PuzzleBoardWithControls = ({ theme, boardTheme, apiProxy, renderControls =
|
|
|
1176
1176
|
return;
|
|
1177
1177
|
}
|
|
1178
1178
|
completionFlowStartedRef.current = true;
|
|
1179
|
+
if (missedMoveIndices.length === 0) {
|
|
1180
|
+
setCompletionRecapDone(true);
|
|
1181
|
+
return;
|
|
1182
|
+
}
|
|
1179
1183
|
setCompletionCheckVisible(true);
|
|
1180
|
-
}, [loadingNextPuzzle, resultStatus, showCompletionRecap]);
|
|
1184
|
+
}, [loadingNextPuzzle, missedMoveIndices, resultStatus, showCompletionRecap]);
|
|
1181
1185
|
useEffect(() => {
|
|
1182
1186
|
if (!completionCheckVisible) {
|
|
1183
1187
|
return;
|
|
@@ -1206,32 +1210,38 @@ const PuzzleBoardWithControls = ({ theme, boardTheme, apiProxy, renderControls =
|
|
|
1206
1210
|
(position.isSolutionRevealed() || !position.isFinished()),
|
|
1207
1211
|
};
|
|
1208
1212
|
const analysisSnapshot = analysis.isOpen && analysis.snapshot ? analysis.snapshot : null;
|
|
1213
|
+
const setupFen = (_a = position === null || position === void 0 ? void 0 : position.fen()) !== null && _a !== void 0 ? _a : '';
|
|
1214
|
+
const playTimeEnabled = Boolean(position) &&
|
|
1215
|
+
!(position === null || position === void 0 ? void 0 : position.isFinished()) &&
|
|
1216
|
+
!analysisSnapshot &&
|
|
1217
|
+
isAnalyzableFen(setupFen);
|
|
1218
|
+
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]);
|
|
1209
1219
|
const resolvedAnalysisBoardWidth = analysisBoardWidth !== null && analysisBoardWidth !== void 0 ? analysisBoardWidth : analysisLayout.boardWidth;
|
|
1210
1220
|
const useHostAnalysisUi = Boolean(renderAnalysisSidebar &&
|
|
1211
1221
|
renderAnalysisContainer &&
|
|
1212
1222
|
(renderEngineEvaluation || (engine === null || engine === void 0 ? void 0 : engine.enabled) === false));
|
|
1213
|
-
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 ||
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
sideToMove: (
|
|
1223
|
+
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(PlayTimeEngineProvider, { fen: setupFen, enabled: playTimeEnabled, options: resolvedPlayTimeEngine, children: [renderAboveBoard === null || renderAboveBoard === void 0 ? void 0 : renderAboveBoard({ fen: setupFen }), 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 ||
|
|
1224
|
+
completionCheckVisible ||
|
|
1225
|
+
isCompletionRecapping, onMissFeedbackChange: setMissFeedback, recapBoard: isCompletionRecapping
|
|
1226
|
+
? {
|
|
1227
|
+
fen: completionRecap.fen,
|
|
1228
|
+
lastMoveUci: completionRecap.lastMoveUci,
|
|
1229
|
+
customArrows: completionRecap.customArrows,
|
|
1230
|
+
animationDuration: completionRecap.animationDuration,
|
|
1231
|
+
}
|
|
1232
|
+
: null }) }), completionCheckVisible && (jsx(BoardCompleteCheckOverlay, { variant: hasIncorrectAttempt || completedAfterMiss || hintUsed
|
|
1233
|
+
? 'partial'
|
|
1234
|
+
: 'success' }))] })] }), renderBoardCaption && (jsx("div", { style: puzzleBoardCaptionSlotStyle(), children: renderBoardCaption({
|
|
1235
|
+
sideToMove: (_b = position === null || position === void 0 ? void 0 : position.getSideToMove()) !== null && _b !== void 0 ? _b : null,
|
|
1226
1236
|
playerColor: position
|
|
1227
1237
|
? position.getPlayerColor()
|
|
1228
1238
|
: null,
|
|
1229
1239
|
incorrectAttempt: resultStatus === 'incorrect',
|
|
1230
1240
|
complete: resultStatus === 'complete',
|
|
1231
1241
|
cleanSolve: !hasIncorrectAttempt,
|
|
1232
|
-
refutationSan: (
|
|
1233
|
-
missPhase: (
|
|
1234
|
-
answerArrowVisible: (
|
|
1242
|
+
refutationSan: (_c = missFeedback === null || missFeedback === void 0 ? void 0 : missFeedback.refutationSan) !== null && _c !== void 0 ? _c : null,
|
|
1243
|
+
missPhase: (_d = missFeedback === null || missFeedback === void 0 ? void 0 : missFeedback.phase) !== null && _d !== void 0 ? _d : null,
|
|
1244
|
+
answerArrowVisible: (_e = missFeedback === null || missFeedback === void 0 ? void 0 : missFeedback.answerArrowVisible) !== null && _e !== void 0 ? _e : false,
|
|
1235
1245
|
completedAfterMiss,
|
|
1236
1246
|
hintUsed,
|
|
1237
1247
|
}) }))] }), jsxs("div", { style: puzzleControlsSlotStyle(controlsPlacement), children: [renderControls(handleHintRequest, handleShowSolution, handleNextPuzzle, resultStatus, {
|
|
@@ -1286,7 +1296,7 @@ const boardOrientationForLine = (side) => side === 'b' ? 'black' : 'white';
|
|
|
1286
1296
|
* tactical puzzles. Mount one instance per drill (key it by line) so its
|
|
1287
1297
|
* internal state resets between lines.
|
|
1288
1298
|
*/
|
|
1289
|
-
const LineBoardWithControls = ({ theme, boardTheme, line, onComplete, onMove, renderControls = defaultRenderLineControls, boardWidth = DEFAULT_PUZZLE_BOARD_WIDTH, opponentMoveDelayMs = DEFAULT_OPPONENT_MOVE_DELAY_MS, }) => {
|
|
1299
|
+
const LineBoardWithControls = ({ theme, boardTheme, line, onComplete, onMove, renderControls = defaultRenderLineControls, renderAboveBoard, playTimeEngine, boardWidth = DEFAULT_PUZZLE_BOARD_WIDTH, opponentMoveDelayMs = DEFAULT_OPPONENT_MOVE_DELAY_MS, }) => {
|
|
1290
1300
|
const chessRef = useRef(new Chess(line.startFen));
|
|
1291
1301
|
const perMoveRef = useRef([]);
|
|
1292
1302
|
const completedRef = useRef(false);
|
|
@@ -1411,7 +1421,9 @@ const LineBoardWithControls = ({ theme, boardTheme, line, onComplete, onMove, re
|
|
|
1411
1421
|
const controlsPlacement = stackControlsBelow
|
|
1412
1422
|
? 'below'
|
|
1413
1423
|
: 'beside';
|
|
1414
|
-
|
|
1424
|
+
const playTimeEnabled = isAnalyzableFen(boardFen);
|
|
1425
|
+
const boardColumn = (jsxs(Fragment, { children: [renderAboveBoard === null || renderAboveBoard === void 0 ? void 0 : renderAboveBoard({ fen: boardFen }), jsx("div", { style: puzzleBoardSlotStyle(), children: jsx(LineBoard, { fen: boardFen, orientation: orientation, trainSide: line.trainSide, draggable: isUserTurn, correctMoveSquare: correctMoveSquare, incorrectMoveSquare: incorrectMoveSquare, lastMoveUci: lastMoveUci, onPieceDrop: handleDrop, boardWidth: boardWidth }) })] }));
|
|
1426
|
+
return (jsx(ThemeProvider, { theme: theme, boardTheme: boardTheme, children: jsxs("div", { style: puzzlePlayRowStyle(controlsPlacement), children: [jsx("div", { style: puzzleBoardColumnStyle(boardWidth, controlsPlacement), children: renderAboveBoard ? (jsx(PlayTimeEngineProvider, { fen: boardFen, enabled: playTimeEnabled, options: playTimeEngine, children: boardColumn })) : (boardColumn) }), jsx("div", { style: puzzleControlsSlotStyle(controlsPlacement), children: renderControls({
|
|
1415
1427
|
trainSide: line.trainSide,
|
|
1416
1428
|
moveNumber,
|
|
1417
1429
|
total,
|
package/dist/index.js
CHANGED
|
@@ -62,7 +62,7 @@ const EMPTY_BOARD_FEN = '8/8/8/8/8/8/8/8 w - - 0 1';
|
|
|
62
62
|
* visible while the next position loads so layout and perspective do not flicker.
|
|
63
63
|
*/
|
|
64
64
|
const PuzzlePlaySurface = ({ position, onFeedback, incInteractionNum, boardWidth, onResumeCorrect, revealAnswerOnIncorrect = false, showAnswerArrowOnIncorrect = false, allowRetryOnIncorrect = true, showRefutationOnIncorrect = false, autoShowWrongMoves = true, refutationEngine, answerArrowColor = reactChessCore.DEFAULT_ANSWER_ARROW_COLOR, positionLocked = false, onMissFeedbackChange, recapBoard = null, }) => {
|
|
65
|
-
var _a, _b, _c, _d, _e
|
|
65
|
+
var _a, _b, _c, _d, _e;
|
|
66
66
|
const [showAnswerArrow, setShowAnswerArrow] = react.useState(false);
|
|
67
67
|
const [incorrectActive, setIncorrectActive] = react.useState(false);
|
|
68
68
|
const attemptMissedRef = react.useRef(false);
|
|
@@ -99,16 +99,14 @@ const PuzzlePlaySurface = ({ position, onFeedback, incInteractionNum, boardWidth
|
|
|
99
99
|
autoShowWrongMoves: useRefutation ? true : autoShowWrongMoves,
|
|
100
100
|
engineOptions: refutationEngine,
|
|
101
101
|
});
|
|
102
|
-
const missPhase =
|
|
102
|
+
const missPhase = missBoard.phase;
|
|
103
103
|
const answerArrowVisible = useRefutation
|
|
104
104
|
? incorrectActive && missPhase === 'answer'
|
|
105
105
|
: showAnswerArrow;
|
|
106
|
-
const overlayIncorrectSquare =
|
|
107
|
-
? missBoard.
|
|
108
|
-
:
|
|
109
|
-
const refutationMoveSquare = useRefutation && incorrectActive
|
|
110
|
-
? missBoard.missSequence.display.refutationMoveSquare
|
|
111
|
-
: null;
|
|
106
|
+
const overlayIncorrectSquare = useRefutation && incorrectActive
|
|
107
|
+
? missBoard.incorrectMoveSquare
|
|
108
|
+
: transientIncorrectSquare;
|
|
109
|
+
const refutationMoveSquare = useRefutation && incorrectActive ? missBoard.refutationMoveSquare : null;
|
|
112
110
|
react.useEffect(() => {
|
|
113
111
|
setShowAnswerArrow(false);
|
|
114
112
|
setIncorrectActive(false);
|
|
@@ -123,14 +121,13 @@ const PuzzlePlaySurface = ({ position, onFeedback, incInteractionNum, boardWidth
|
|
|
123
121
|
position,
|
|
124
122
|
]);
|
|
125
123
|
react.useEffect(() => {
|
|
126
|
-
var _a, _b;
|
|
127
124
|
if (!onMissFeedbackChange) {
|
|
128
125
|
return;
|
|
129
126
|
}
|
|
130
127
|
if (useRefutation && incorrectActive) {
|
|
131
128
|
onMissFeedbackChange({
|
|
132
129
|
refutationSan: missBoard.refutation.refutationSan,
|
|
133
|
-
phase:
|
|
130
|
+
phase: missBoard.phase,
|
|
134
131
|
answerArrowVisible,
|
|
135
132
|
});
|
|
136
133
|
return;
|
|
@@ -147,7 +144,7 @@ const PuzzlePlaySurface = ({ position, onFeedback, incInteractionNum, boardWidth
|
|
|
147
144
|
}, [
|
|
148
145
|
answerArrowVisible,
|
|
149
146
|
incorrectActive,
|
|
150
|
-
|
|
147
|
+
missBoard.phase,
|
|
151
148
|
missBoard.refutation.refutationSan,
|
|
152
149
|
onMissFeedbackChange,
|
|
153
150
|
showAnswerArrow,
|
|
@@ -187,12 +184,8 @@ const PuzzlePlaySurface = ({ position, onFeedback, incInteractionNum, boardWidth
|
|
|
187
184
|
? recapBoard.lastMoveUci
|
|
188
185
|
: useRefutation && incorrectActive
|
|
189
186
|
? missBoard.lastMoveUci
|
|
190
|
-
: ((
|
|
191
|
-
const missLocked = useRefutation &&
|
|
192
|
-
incorrectActive &&
|
|
193
|
-
(missBoard.boardAnimating ||
|
|
194
|
-
missPhase === 'wrong' ||
|
|
195
|
-
missPhase === 'refutation');
|
|
187
|
+
: ((_c = position === null || position === void 0 ? void 0 : position.getLastMoveUci()) !== null && _c !== void 0 ? _c : null);
|
|
188
|
+
const missLocked = useRefutation && incorrectActive && missBoard.inputLocked;
|
|
196
189
|
const arePiecesDraggable = !isRecapping &&
|
|
197
190
|
position !== null &&
|
|
198
191
|
!positionLocked &&
|
|
@@ -222,7 +215,9 @@ const PuzzlePlaySurface = ({ position, onFeedback, incInteractionNum, boardWidth
|
|
|
222
215
|
});
|
|
223
216
|
if (!guess.accepted) {
|
|
224
217
|
attemptMissedRef.current = true;
|
|
225
|
-
|
|
218
|
+
if (!useRefutation) {
|
|
219
|
+
showIncorrectMove(sourceSquare);
|
|
220
|
+
}
|
|
226
221
|
onFeedback({
|
|
227
222
|
index: position.getIndex(),
|
|
228
223
|
guess: { sourceSquare, targetSquare, piece },
|
|
@@ -302,7 +297,11 @@ const PuzzlePlaySurface = ({ position, onFeedback, incInteractionNum, boardWidth
|
|
|
302
297
|
showCorrectMove(targetSquare, finishCorrectFeedback);
|
|
303
298
|
return true;
|
|
304
299
|
};
|
|
305
|
-
return hasBoard ? (jsxRuntime.jsx(reactChessCore.HighlightChessboard, { boardWidth: boardWidth, checkSquare: isRecapping ? '' : ((
|
|
300
|
+
return hasBoard ? (jsxRuntime.jsx(reactChessCore.HighlightChessboard, { boardWidth: boardWidth, checkSquare: isRecapping ? '' : ((_d = position === null || position === void 0 ? void 0 : position.getCheckSquare()) !== null && _d !== void 0 ? _d : ''), hintSquare: isRecapping ? null : ((_e = position === null || position === void 0 ? void 0 : position.getHintSquare()) !== null && _e !== void 0 ? _e : null), incorrectMoveSquare: isRecapping ? null : overlayIncorrectSquare, refutationMoveSquare: isRecapping ? null : refutationMoveSquare, correctMoveSquare: isRecapping ? null : correctMoveSquare, customArrows: customArrows, lastMoveUci: lastMoveUci, onPieceDrop: onPieceDrop, position: displayFen, boardOrientation: boardOrientation, arePiecesDraggable: arePiecesDraggable, areArrowsAllowed: false, promotionDialogVariant: "modal", animationDuration: isRecapping
|
|
301
|
+
? recapBoard.animationDuration
|
|
302
|
+
: useRefutation && incorrectActive
|
|
303
|
+
? missBoard.animationDuration
|
|
304
|
+
: 0 }, revision)) : null;
|
|
306
305
|
};
|
|
307
306
|
|
|
308
307
|
const PuzzleBoard = ({ position, onFeedback, incInteractionNum, boardWidth, revealAnswerOnIncorrect = false, showAnswerArrowOnIncorrect = false, allowRetryOnIncorrect = true, answerArrowColor, }) => (jsxRuntime.jsx(PuzzlePlaySurface, { position: position, onFeedback: onFeedback, incInteractionNum: incInteractionNum, boardWidth: boardWidth, revealAnswerOnIncorrect: revealAnswerOnIncorrect, showAnswerArrowOnIncorrect: showAnswerArrowOnIncorrect, allowRetryOnIncorrect: allowRetryOnIncorrect, answerArrowColor: answerArrowColor }));
|
|
@@ -371,6 +370,7 @@ const usePuzzleCompletionRecap = ({ source, active, onComplete, }) => {
|
|
|
371
370
|
segmentStartFen: startFen,
|
|
372
371
|
setupUci,
|
|
373
372
|
onComplete,
|
|
373
|
+
completeImmediatelyWhenNoMisses: true,
|
|
374
374
|
resolveFen,
|
|
375
375
|
});
|
|
376
376
|
};
|
|
@@ -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, renderAboveBoard, 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
|
|
@@ -1177,8 +1177,12 @@ const PuzzleBoardWithControls = ({ theme, boardTheme, apiProxy, renderControls =
|
|
|
1177
1177
|
return;
|
|
1178
1178
|
}
|
|
1179
1179
|
completionFlowStartedRef.current = true;
|
|
1180
|
+
if (missedMoveIndices.length === 0) {
|
|
1181
|
+
setCompletionRecapDone(true);
|
|
1182
|
+
return;
|
|
1183
|
+
}
|
|
1180
1184
|
setCompletionCheckVisible(true);
|
|
1181
|
-
}, [loadingNextPuzzle, resultStatus, showCompletionRecap]);
|
|
1185
|
+
}, [loadingNextPuzzle, missedMoveIndices, resultStatus, showCompletionRecap]);
|
|
1182
1186
|
react.useEffect(() => {
|
|
1183
1187
|
if (!completionCheckVisible) {
|
|
1184
1188
|
return;
|
|
@@ -1207,32 +1211,38 @@ const PuzzleBoardWithControls = ({ theme, boardTheme, apiProxy, renderControls =
|
|
|
1207
1211
|
(position.isSolutionRevealed() || !position.isFinished()),
|
|
1208
1212
|
};
|
|
1209
1213
|
const analysisSnapshot = analysis.isOpen && analysis.snapshot ? analysis.snapshot : null;
|
|
1214
|
+
const setupFen = (_a = position === null || position === void 0 ? void 0 : position.fen()) !== null && _a !== void 0 ? _a : '';
|
|
1215
|
+
const playTimeEnabled = Boolean(position) &&
|
|
1216
|
+
!(position === null || position === void 0 ? void 0 : position.isFinished()) &&
|
|
1217
|
+
!analysisSnapshot &&
|
|
1218
|
+
reactChessCore.isAnalyzableFen(setupFen);
|
|
1219
|
+
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]);
|
|
1210
1220
|
const resolvedAnalysisBoardWidth = analysisBoardWidth !== null && analysisBoardWidth !== void 0 ? analysisBoardWidth : analysisLayout.boardWidth;
|
|
1211
1221
|
const useHostAnalysisUi = Boolean(renderAnalysisSidebar &&
|
|
1212
1222
|
renderAnalysisContainer &&
|
|
1213
1223
|
(renderEngineEvaluation || (engine === null || engine === void 0 ? void 0 : engine.enabled) === false));
|
|
1214
|
-
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 ||
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
sideToMove: (
|
|
1224
|
+
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(reactChessCore.PlayTimeEngineProvider, { fen: setupFen, enabled: playTimeEnabled, options: resolvedPlayTimeEngine, children: [renderAboveBoard === null || renderAboveBoard === void 0 ? void 0 : renderAboveBoard({ fen: setupFen }), 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 ||
|
|
1225
|
+
completionCheckVisible ||
|
|
1226
|
+
isCompletionRecapping, onMissFeedbackChange: setMissFeedback, recapBoard: isCompletionRecapping
|
|
1227
|
+
? {
|
|
1228
|
+
fen: completionRecap.fen,
|
|
1229
|
+
lastMoveUci: completionRecap.lastMoveUci,
|
|
1230
|
+
customArrows: completionRecap.customArrows,
|
|
1231
|
+
animationDuration: completionRecap.animationDuration,
|
|
1232
|
+
}
|
|
1233
|
+
: null }) }), completionCheckVisible && (jsxRuntime.jsx(reactChessCore.BoardCompleteCheckOverlay, { variant: hasIncorrectAttempt || completedAfterMiss || hintUsed
|
|
1234
|
+
? 'partial'
|
|
1235
|
+
: 'success' }))] })] }), renderBoardCaption && (jsxRuntime.jsx("div", { style: puzzleBoardCaptionSlotStyle(), children: renderBoardCaption({
|
|
1236
|
+
sideToMove: (_b = position === null || position === void 0 ? void 0 : position.getSideToMove()) !== null && _b !== void 0 ? _b : null,
|
|
1227
1237
|
playerColor: position
|
|
1228
1238
|
? position.getPlayerColor()
|
|
1229
1239
|
: null,
|
|
1230
1240
|
incorrectAttempt: resultStatus === 'incorrect',
|
|
1231
1241
|
complete: resultStatus === 'complete',
|
|
1232
1242
|
cleanSolve: !hasIncorrectAttempt,
|
|
1233
|
-
refutationSan: (
|
|
1234
|
-
missPhase: (
|
|
1235
|
-
answerArrowVisible: (
|
|
1243
|
+
refutationSan: (_c = missFeedback === null || missFeedback === void 0 ? void 0 : missFeedback.refutationSan) !== null && _c !== void 0 ? _c : null,
|
|
1244
|
+
missPhase: (_d = missFeedback === null || missFeedback === void 0 ? void 0 : missFeedback.phase) !== null && _d !== void 0 ? _d : null,
|
|
1245
|
+
answerArrowVisible: (_e = missFeedback === null || missFeedback === void 0 ? void 0 : missFeedback.answerArrowVisible) !== null && _e !== void 0 ? _e : false,
|
|
1236
1246
|
completedAfterMiss,
|
|
1237
1247
|
hintUsed,
|
|
1238
1248
|
}) }))] }), jsxRuntime.jsxs("div", { style: puzzleControlsSlotStyle(controlsPlacement), children: [renderControls(handleHintRequest, handleShowSolution, handleNextPuzzle, resultStatus, {
|
|
@@ -1287,7 +1297,7 @@ const boardOrientationForLine = (side) => side === 'b' ? 'black' : 'white';
|
|
|
1287
1297
|
* tactical puzzles. Mount one instance per drill (key it by line) so its
|
|
1288
1298
|
* internal state resets between lines.
|
|
1289
1299
|
*/
|
|
1290
|
-
const LineBoardWithControls = ({ theme, boardTheme, line, onComplete, onMove, renderControls = defaultRenderLineControls, boardWidth = DEFAULT_PUZZLE_BOARD_WIDTH, opponentMoveDelayMs = DEFAULT_OPPONENT_MOVE_DELAY_MS, }) => {
|
|
1300
|
+
const LineBoardWithControls = ({ theme, boardTheme, line, onComplete, onMove, renderControls = defaultRenderLineControls, renderAboveBoard, playTimeEngine, boardWidth = DEFAULT_PUZZLE_BOARD_WIDTH, opponentMoveDelayMs = DEFAULT_OPPONENT_MOVE_DELAY_MS, }) => {
|
|
1291
1301
|
const chessRef = react.useRef(new chess_js.Chess(line.startFen));
|
|
1292
1302
|
const perMoveRef = react.useRef([]);
|
|
1293
1303
|
const completedRef = react.useRef(false);
|
|
@@ -1412,7 +1422,9 @@ const LineBoardWithControls = ({ theme, boardTheme, line, onComplete, onMove, re
|
|
|
1412
1422
|
const controlsPlacement = stackControlsBelow
|
|
1413
1423
|
? 'below'
|
|
1414
1424
|
: 'beside';
|
|
1415
|
-
|
|
1425
|
+
const playTimeEnabled = reactChessCore.isAnalyzableFen(boardFen);
|
|
1426
|
+
const boardColumn = (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [renderAboveBoard === null || renderAboveBoard === void 0 ? void 0 : renderAboveBoard({ fen: boardFen }), jsxRuntime.jsx("div", { style: puzzleBoardSlotStyle(), children: jsxRuntime.jsx(LineBoard, { fen: boardFen, orientation: orientation, trainSide: line.trainSide, draggable: isUserTurn, correctMoveSquare: correctMoveSquare, incorrectMoveSquare: incorrectMoveSquare, lastMoveUci: lastMoveUci, onPieceDrop: handleDrop, boardWidth: boardWidth }) })] }));
|
|
1427
|
+
return (jsxRuntime.jsx(reactChessCore.ThemeProvider, { theme: theme, boardTheme: boardTheme, children: jsxRuntime.jsxs("div", { style: puzzlePlayRowStyle(controlsPlacement), children: [jsxRuntime.jsx("div", { style: puzzleBoardColumnStyle(boardWidth, controlsPlacement), children: renderAboveBoard ? (jsxRuntime.jsx(reactChessCore.PlayTimeEngineProvider, { fen: boardFen, enabled: playTimeEnabled, options: playTimeEngine, children: boardColumn })) : (boardColumn) }), jsxRuntime.jsx("div", { style: puzzleControlsSlotStyle(controlsPlacement), children: renderControls({
|
|
1416
1428
|
trainSide: line.trainSide,
|
|
1417
1429
|
moveNumber,
|
|
1418
1430
|
total,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-chess-puzzle-kit",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.9",
|
|
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",
|
|
@@ -76,7 +76,7 @@
|
|
|
76
76
|
"jest": "^29.7.0",
|
|
77
77
|
"jest-environment-jsdom": "^29.7.0",
|
|
78
78
|
"react": "^18.3.1",
|
|
79
|
-
"react-chess-core": "^0.1.
|
|
79
|
+
"react-chess-core": "^0.1.12",
|
|
80
80
|
"react-chessboard": "^4.7.1",
|
|
81
81
|
"react-dom": "^18.3.1",
|
|
82
82
|
"storybook": "^8.2.9",
|