react-chess-core 0.1.5 → 0.1.6
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/features/chessboard/BoardCompleteCheckOverlay.d.ts +2 -0
- package/dist/features/chessboard/HighlightChessboard.d.ts +3 -4
- package/dist/features/chessboard/IncorrectMoveXBadge.d.ts +2 -0
- package/dist/features/chessboard/boardArrowColors.d.ts +13 -0
- package/dist/features/chessboard/createFeedbackSquareRenderer.d.ts +5 -1
- package/dist/features/chessboard/index.d.ts +3 -0
- package/dist/features/chessboard/lastMoveArrow.d.ts +3 -5
- package/dist/features/training/expectedMoveDrop.d.ts +9 -4
- package/dist/features/training/index.d.ts +2 -0
- package/dist/features/training/useIncorrectMoveFeedback.d.ts +6 -0
- package/dist/features/training/useTrainingMoveFeedback.d.ts +22 -0
- package/dist/index.esm.js +158 -31
- package/dist/index.js +163 -30
- package/dist/stories/Chessboard.stories.d.ts +1 -0
- package/package.json +1 -1
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
export interface HighlightChessboardProps {
|
|
2
2
|
checkSquare: string;
|
|
3
3
|
hintSquare: string | null;
|
|
4
|
-
|
|
4
|
+
/** Origin square of a rejected training move — shows a red X on the snapped-back piece. */
|
|
5
|
+
incorrectMoveSquare?: string | null;
|
|
5
6
|
/** Destination square of the last correct training move — shows a green check. */
|
|
6
7
|
correctMoveSquare?: string | null;
|
|
7
8
|
/** UCI of the move that led to the current position (shows a last-move arrow). */
|
|
8
9
|
lastMoveUci?: string | null;
|
|
9
|
-
/** Override the default last-move arrow color. */
|
|
10
|
-
lastMoveArrowColor?: string;
|
|
11
10
|
/** Enable click-to-move when `onPieceDrop` is provided. Defaults to true. */
|
|
12
11
|
clickToMove?: boolean;
|
|
13
12
|
[key: string]: any;
|
|
14
13
|
}
|
|
15
|
-
export declare const HighlightChessboard: ({ checkSquare, hintSquare, incorrectMoveSquare, correctMoveSquare, lastMoveUci,
|
|
14
|
+
export declare const HighlightChessboard: ({ checkSquare, hintSquare, incorrectMoveSquare, correctMoveSquare, lastMoveUci, clickToMove, customSquareStyles: extraSquareStyles, customArrows, customBoardStyle, onPieceDrop, position, arePiecesDraggable, autoPromoteToQueen, isDraggablePiece, onPromotionCheck, onSquareClick, onPromotionPieceSelect, onPieceDragBegin, showPromotionDialog: showPromotionDialogProp, promotionToSquare: promotionToSquareProp, ...props }: HighlightChessboardProps) => import("react").JSX.Element;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Board arrow colors — change these values to update arrows app-wide.
|
|
3
|
+
*/
|
|
4
|
+
export declare const boardArrowColors: {
|
|
5
|
+
/** Arrow showing the move that reached the current position. */
|
|
6
|
+
readonly lastMove: "rgba(130, 130, 130, 0.75)";
|
|
7
|
+
/** Arrow showing the correct / answer move during training. */
|
|
8
|
+
readonly answer: "#1976d2";
|
|
9
|
+
};
|
|
10
|
+
/** @deprecated Use {@link boardArrowColors.lastMove} */
|
|
11
|
+
export declare const DEFAULT_LAST_MOVE_ARROW_COLOR: "rgba(130, 130, 130, 0.75)";
|
|
12
|
+
/** @deprecated Use {@link boardArrowColors.answer} */
|
|
13
|
+
export declare const DEFAULT_ANSWER_ARROW_COLOR: "#1976d2";
|
|
@@ -1,3 +1,7 @@
|
|
|
1
1
|
import type { FC } from 'react';
|
|
2
2
|
import type { CustomSquareProps } from 'react-chessboard/dist/chessboard/types';
|
|
3
|
-
export
|
|
3
|
+
export type FeedbackSquareRendererOptions = {
|
|
4
|
+
correctMoveSquare?: string | null;
|
|
5
|
+
incorrectMoveSquare?: string | null;
|
|
6
|
+
};
|
|
7
|
+
export declare function createFeedbackSquareRenderer({ correctMoveSquare, incorrectMoveSquare, }: FeedbackSquareRendererOptions): FC<CustomSquareProps> | undefined;
|
|
@@ -3,5 +3,8 @@ export * from './chessboardTheme';
|
|
|
3
3
|
export * from './ChessboardDnDProvider';
|
|
4
4
|
export * from './HighlightChessboard';
|
|
5
5
|
export * from './CorrectMoveCheckBadge';
|
|
6
|
+
export * from './IncorrectMoveXBadge';
|
|
7
|
+
export * from './BoardCompleteCheckOverlay';
|
|
6
8
|
export * from './boardSquareHighlightColors';
|
|
9
|
+
export * from './boardArrowColors';
|
|
7
10
|
export * from './lastMoveArrow';
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
export type ChessboardArrow = [string, string, string];
|
|
2
|
-
|
|
3
|
-
export declare const
|
|
4
|
-
export declare const uciToArrow: (uci: string, color?: string) => ChessboardArrow;
|
|
5
|
-
export declare const lastMoveArrowFromUci: (uci: string | null | undefined, color?: string) => ChessboardArrow[];
|
|
2
|
+
export declare const uciToArrow: (uci: string) => ChessboardArrow;
|
|
3
|
+
export declare const lastMoveArrowFromUci: (uci: string | null | undefined) => ChessboardArrow[];
|
|
6
4
|
/** UCI of the move that produced the position at {@link plyIndex}. */
|
|
7
5
|
export declare const lastMoveUciAtPly: (movesUci: readonly string[], plyIndex: number) => string | null;
|
|
8
|
-
export declare const mergeCustomArrowsWithLastMove: (customArrows: ChessboardArrow[] | undefined, lastMoveUci: string | null | undefined
|
|
6
|
+
export declare const mergeCustomArrowsWithLastMove: (customArrows: ChessboardArrow[] | undefined, lastMoveUci: string | null | undefined) => ChessboardArrow[];
|
|
@@ -1,20 +1,25 @@
|
|
|
1
|
+
export type ExpectedMoveAttempt = {
|
|
2
|
+
uci: string;
|
|
3
|
+
sourceSquare: string;
|
|
4
|
+
targetSquare: string;
|
|
5
|
+
};
|
|
1
6
|
export type ExpectedMoveDropResult = {
|
|
2
7
|
kind: 'ignored';
|
|
3
8
|
} | {
|
|
4
9
|
kind: 'illegal';
|
|
5
10
|
} | {
|
|
6
11
|
kind: 'correct';
|
|
7
|
-
|
|
12
|
+
attempt: ExpectedMoveAttempt;
|
|
8
13
|
} | {
|
|
9
14
|
kind: 'incorrect';
|
|
10
|
-
|
|
15
|
+
attempt: ExpectedMoveAttempt;
|
|
11
16
|
};
|
|
12
17
|
export type CreateExpectedMoveDropHandlerOptions = {
|
|
13
18
|
fen: string;
|
|
14
19
|
expectedUci: string | null | undefined;
|
|
15
20
|
enabled: boolean;
|
|
16
|
-
onCorrect: (
|
|
17
|
-
onIncorrect: (
|
|
21
|
+
onCorrect: (attempt: ExpectedMoveAttempt) => void;
|
|
22
|
+
onIncorrect: (attempt: ExpectedMoveAttempt) => void;
|
|
18
23
|
};
|
|
19
24
|
/**
|
|
20
25
|
* Evaluate a training drop without mutating board position.
|
|
@@ -3,4 +3,6 @@ export * from './expectedMoveDrop';
|
|
|
3
3
|
export * from './useBoardRevision';
|
|
4
4
|
export * from './correctMoveFeedbackMs';
|
|
5
5
|
export * from './useCorrectMoveFeedback';
|
|
6
|
+
export * from './useIncorrectMoveFeedback';
|
|
7
|
+
export * from './useTrainingMoveFeedback';
|
|
6
8
|
export * from './miss';
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type CreateExpectedMoveDropHandlerOptions, type ExpectedMoveAttempt } from './expectedMoveDrop';
|
|
2
|
+
export type CreateTrainingDropHandlerOptions = Omit<CreateExpectedMoveDropHandlerOptions, 'onCorrect' | 'onIncorrect'> & {
|
|
3
|
+
onCorrect?: (attempt: ExpectedMoveAttempt) => void;
|
|
4
|
+
onIncorrect?: (attempt: ExpectedMoveAttempt) => void;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* Shared correct/incorrect move overlays for training boards.
|
|
8
|
+
* Incorrect feedback always uses the drag origin square (snapped-back piece).
|
|
9
|
+
*/
|
|
10
|
+
export declare function useTrainingMoveFeedback(delayMs?: number): {
|
|
11
|
+
correctMoveSquare: string | null;
|
|
12
|
+
incorrectMoveSquare: string | null;
|
|
13
|
+
showCorrectMove: (targetSquare: string, onComplete?: () => void) => void;
|
|
14
|
+
showIncorrectMove: (originSquare: string, onComplete?: () => void) => void;
|
|
15
|
+
clearMoveFeedback: () => void;
|
|
16
|
+
clearCorrectMoveFeedback: () => void;
|
|
17
|
+
clearIncorrectMoveFeedback: () => void;
|
|
18
|
+
isShowingCorrectMove: boolean;
|
|
19
|
+
isShowingIncorrectMove: boolean;
|
|
20
|
+
isShowingMoveFeedback: boolean;
|
|
21
|
+
createDropHandler: ({ onCorrect, onIncorrect, ...options }: CreateTrainingDropHandlerOptions) => (sourceSquare: string, targetSquare: string, piece: string) => boolean;
|
|
22
|
+
};
|
package/dist/index.esm.js
CHANGED
|
@@ -1746,7 +1746,7 @@ const boardSquareHighlightColors = {
|
|
|
1746
1746
|
captureTarget: 'radial-gradient(circle, rgba(0, 0, 0, 0.18) 72%, transparent 72%)',
|
|
1747
1747
|
};
|
|
1748
1748
|
|
|
1749
|
-
const badgeStyle = {
|
|
1749
|
+
const badgeStyle$2 = {
|
|
1750
1750
|
position: 'absolute',
|
|
1751
1751
|
right: '6%',
|
|
1752
1752
|
bottom: '6%',
|
|
@@ -1766,29 +1766,69 @@ const badgeStyle = {
|
|
|
1766
1766
|
};
|
|
1767
1767
|
/** Green circle with a white check, anchored to the bottom-right of a square
|
|
1768
1768
|
* square (over the piece). */
|
|
1769
|
-
const CorrectMoveCheckBadge = () => (jsx("span", { "aria-hidden": true, style: badgeStyle, children: jsx("svg", { viewBox: "0 0 12 12", width: "62%", height: "62%", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: jsx("path", { d: "M2.5 6.2 5 8.7 9.5 3.8", stroke: "#fff", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round" }) }) }));
|
|
1769
|
+
const CorrectMoveCheckBadge = () => (jsx("span", { "aria-hidden": true, style: badgeStyle$2, children: jsx("svg", { viewBox: "0 0 12 12", width: "62%", height: "62%", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: jsx("path", { d: "M2.5 6.2 5 8.7 9.5 3.8", stroke: "#fff", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round" }) }) }));
|
|
1770
1770
|
|
|
1771
|
-
const
|
|
1771
|
+
const badgeStyle$1 = {
|
|
1772
|
+
position: 'absolute',
|
|
1773
|
+
right: '6%',
|
|
1774
|
+
bottom: '6%',
|
|
1775
|
+
width: '26%',
|
|
1776
|
+
height: '26%',
|
|
1777
|
+
minWidth: 14,
|
|
1778
|
+
minHeight: 14,
|
|
1779
|
+
maxWidth: 26,
|
|
1780
|
+
maxHeight: 26,
|
|
1781
|
+
borderRadius: '50%',
|
|
1782
|
+
backgroundColor: '#c62828',
|
|
1783
|
+
display: 'flex',
|
|
1784
|
+
alignItems: 'center',
|
|
1785
|
+
justifyContent: 'center',
|
|
1786
|
+
boxShadow: '0 1px 3px rgba(0, 0, 0, 0.35)',
|
|
1787
|
+
pointerEvents: 'none',
|
|
1788
|
+
};
|
|
1789
|
+
/** Red circle with a white X, anchored to the bottom-right of a square. */
|
|
1790
|
+
const IncorrectMoveXBadge = () => (jsx("span", { "aria-hidden": true, style: badgeStyle$1, children: jsx("svg", { viewBox: "0 0 12 12", width: "58%", height: "58%", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: jsx("path", { d: "M3.2 3.2 8.8 8.8M8.8 3.2 3.2 8.8", stroke: "#fff", strokeWidth: "1.8", strokeLinecap: "round" }) }) }));
|
|
1791
|
+
|
|
1792
|
+
const overlayStyle$2 = {
|
|
1772
1793
|
position: 'absolute',
|
|
1773
1794
|
inset: 0,
|
|
1774
1795
|
pointerEvents: 'none',
|
|
1775
1796
|
zIndex: 20,
|
|
1776
1797
|
overflow: 'visible',
|
|
1777
1798
|
};
|
|
1778
|
-
function createFeedbackSquareRenderer(correctMoveSquare) {
|
|
1799
|
+
function createFeedbackSquareRenderer({ correctMoveSquare = null, incorrectMoveSquare = null, }) {
|
|
1800
|
+
if (!correctMoveSquare && !incorrectMoveSquare) {
|
|
1801
|
+
return undefined;
|
|
1802
|
+
}
|
|
1779
1803
|
return function FeedbackSquare({ children, style, square, ref }) {
|
|
1780
|
-
return (jsxs("div", { ref: ref, style: Object.assign(Object.assign({}, style), { position: 'relative', overflow: 'visible' }), children: [children, square === correctMoveSquare ? (jsx("div", { style: overlayStyle$
|
|
1804
|
+
return (jsxs("div", { ref: ref, style: Object.assign(Object.assign({}, style), { position: 'relative', overflow: 'visible' }), children: [children, square === correctMoveSquare ? (jsx("div", { style: overlayStyle$2, children: jsx(CorrectMoveCheckBadge, {}) })) : null, square === incorrectMoveSquare ? (jsx("div", { style: overlayStyle$2, children: jsx(IncorrectMoveXBadge, {}) })) : null] }));
|
|
1781
1805
|
};
|
|
1782
1806
|
}
|
|
1783
1807
|
|
|
1784
|
-
/**
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
const
|
|
1808
|
+
/**
|
|
1809
|
+
* Board arrow colors — change these values to update arrows app-wide.
|
|
1810
|
+
*/
|
|
1811
|
+
const boardArrowColors = {
|
|
1812
|
+
/** Arrow showing the move that reached the current position. */
|
|
1813
|
+
lastMove: 'rgba(130, 130, 130, 0.75)',
|
|
1814
|
+
/** Arrow showing the correct / answer move during training. */
|
|
1815
|
+
answer: '#1976d2',
|
|
1816
|
+
};
|
|
1817
|
+
/** @deprecated Use {@link boardArrowColors.lastMove} */
|
|
1818
|
+
const DEFAULT_LAST_MOVE_ARROW_COLOR = boardArrowColors.lastMove;
|
|
1819
|
+
/** @deprecated Use {@link boardArrowColors.answer} */
|
|
1820
|
+
const DEFAULT_ANSWER_ARROW_COLOR = boardArrowColors.answer;
|
|
1821
|
+
|
|
1822
|
+
const uciToArrow = (uci) => [
|
|
1823
|
+
uci.slice(0, 2),
|
|
1824
|
+
uci.slice(2, 4),
|
|
1825
|
+
boardArrowColors.lastMove,
|
|
1826
|
+
];
|
|
1827
|
+
const lastMoveArrowFromUci = (uci) => {
|
|
1788
1828
|
if (!uci || uci.length < 4) {
|
|
1789
1829
|
return [];
|
|
1790
1830
|
}
|
|
1791
|
-
return [uciToArrow(uci
|
|
1831
|
+
return [uciToArrow(uci)];
|
|
1792
1832
|
};
|
|
1793
1833
|
/** UCI of the move that produced the position at {@link plyIndex}. */
|
|
1794
1834
|
const lastMoveUciAtPly = (movesUci, plyIndex) => {
|
|
@@ -1798,8 +1838,8 @@ const lastMoveUciAtPly = (movesUci, plyIndex) => {
|
|
|
1798
1838
|
}
|
|
1799
1839
|
return (_a = movesUci[plyIndex - 1]) !== null && _a !== void 0 ? _a : null;
|
|
1800
1840
|
};
|
|
1801
|
-
const mergeCustomArrowsWithLastMove = (customArrows, lastMoveUci
|
|
1802
|
-
const lastMove = lastMoveArrowFromUci(lastMoveUci
|
|
1841
|
+
const mergeCustomArrowsWithLastMove = (customArrows, lastMoveUci) => {
|
|
1842
|
+
const lastMove = lastMoveArrowFromUci(lastMoveUci);
|
|
1803
1843
|
if (!lastMove.length) {
|
|
1804
1844
|
return customArrows !== null && customArrows !== void 0 ? customArrows : [];
|
|
1805
1845
|
}
|
|
@@ -1965,20 +2005,15 @@ const getCheckHighlighting = (checkSquare) => {
|
|
|
1965
2005
|
styles[checkSquare] = { backgroundColor: boardSquareHighlightColors.check };
|
|
1966
2006
|
return styles;
|
|
1967
2007
|
};
|
|
1968
|
-
const getFeedbackHighlighting = (hintSquare
|
|
2008
|
+
const getFeedbackHighlighting = (hintSquare) => {
|
|
1969
2009
|
const styles = {};
|
|
1970
2010
|
if (hintSquare) {
|
|
1971
2011
|
styles[hintSquare] = { backgroundColor: boardSquareHighlightColors.hint };
|
|
1972
2012
|
}
|
|
1973
|
-
if (incorrectMoveSquare) {
|
|
1974
|
-
styles[incorrectMoveSquare] = {
|
|
1975
|
-
backgroundColor: boardSquareHighlightColors.incorrect,
|
|
1976
|
-
};
|
|
1977
|
-
}
|
|
1978
2013
|
return styles;
|
|
1979
2014
|
};
|
|
1980
2015
|
const HighlightChessboard = (_a) => {
|
|
1981
|
-
var { checkSquare, hintSquare, incorrectMoveSquare, correctMoveSquare = null, lastMoveUci = null,
|
|
2016
|
+
var { checkSquare, hintSquare, incorrectMoveSquare = null, correctMoveSquare = null, lastMoveUci = null, clickToMove, customSquareStyles: extraSquareStyles, customArrows, customBoardStyle, onPieceDrop, position, arePiecesDraggable, autoPromoteToQueen, isDraggablePiece, onPromotionCheck, onSquareClick, onPromotionPieceSelect, onPieceDragBegin, showPromotionDialog: showPromotionDialogProp, promotionToSquare: promotionToSquareProp } = _a, props = __rest(_a, ["checkSquare", "hintSquare", "incorrectMoveSquare", "correctMoveSquare", "lastMoveUci", "clickToMove", "customSquareStyles", "customArrows", "customBoardStyle", "onPieceDrop", "position", "arePiecesDraggable", "autoPromoteToQueen", "isDraggablePiece", "onPromotionCheck", "onSquareClick", "onPromotionPieceSelect", "onPieceDragBegin", "showPromotionDialog", "promotionToSquare"]);
|
|
1982
2017
|
const { customDarkSquareStyle, customLightSquareStyle } = useChessboardTheme();
|
|
1983
2018
|
const clickToMoveEnabled = clickToMove !== false && typeof onPieceDrop === 'function';
|
|
1984
2019
|
const { clickSquareStyles, handleSquareClick, handlePromotionPieceSelect, handlePieceDragBegin, showPromotionDialog: clickPromotionDialog, promotionToSquare: clickPromotionToSquare, } = useClickToMove({
|
|
@@ -1994,12 +2029,13 @@ const HighlightChessboard = (_a) => {
|
|
|
1994
2029
|
onPieceDragBegin,
|
|
1995
2030
|
});
|
|
1996
2031
|
const checkStyles = getCheckHighlighting(checkSquare);
|
|
1997
|
-
const feedbackStyles = getFeedbackHighlighting(hintSquare
|
|
2032
|
+
const feedbackStyles = getFeedbackHighlighting(hintSquare);
|
|
1998
2033
|
const customSquareStyles = Object.assign(Object.assign(Object.assign(Object.assign({}, clickSquareStyles), checkStyles), feedbackStyles), extraSquareStyles);
|
|
1999
|
-
const customSquare = useMemo(() =>
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2034
|
+
const customSquare = useMemo(() => createFeedbackSquareRenderer({
|
|
2035
|
+
correctMoveSquare,
|
|
2036
|
+
incorrectMoveSquare,
|
|
2037
|
+
}), [correctMoveSquare, incorrectMoveSquare]);
|
|
2038
|
+
const mergedCustomArrows = useMemo(() => mergeCustomArrowsWithLastMove(customArrows, lastMoveUci), [customArrows, lastMoveUci]);
|
|
2003
2039
|
const promotionControlProps = clickPromotionDialog
|
|
2004
2040
|
? {
|
|
2005
2041
|
showPromotionDialog: true,
|
|
@@ -2015,6 +2051,29 @@ const HighlightChessboard = (_a) => {
|
|
|
2015
2051
|
return (jsx(Chessboard, Object.assign({ customDarkSquareStyle: customDarkSquareStyle, customLightSquareStyle: customLightSquareStyle, customSquareStyles: customSquareStyles, customSquare: customSquare, customBoardStyle: Object.assign(Object.assign({}, nonSelectableBoardStyle), customBoardStyle), position: position, arePiecesDraggable: arePiecesDraggable, autoPromoteToQueen: autoPromoteToQueen, isDraggablePiece: isDraggablePiece, onPromotionCheck: onPromotionCheck, onPieceDrop: onPieceDrop, onSquareClick: clickToMoveEnabled ? handleSquareClick : onSquareClick, onPromotionPieceSelect: clickToMoveEnabled ? handlePromotionPieceSelect : onPromotionPieceSelect, onPieceDragBegin: clickToMoveEnabled ? handlePieceDragBegin : onPieceDragBegin, customArrows: mergedCustomArrows }, promotionControlProps, props)));
|
|
2016
2052
|
};
|
|
2017
2053
|
|
|
2054
|
+
const overlayStyle$1 = {
|
|
2055
|
+
position: 'absolute',
|
|
2056
|
+
inset: 0,
|
|
2057
|
+
display: 'flex',
|
|
2058
|
+
alignItems: 'center',
|
|
2059
|
+
justifyContent: 'center',
|
|
2060
|
+
pointerEvents: 'none',
|
|
2061
|
+
zIndex: 10,
|
|
2062
|
+
borderRadius: 4,
|
|
2063
|
+
};
|
|
2064
|
+
const badgeStyle = {
|
|
2065
|
+
width: '58%',
|
|
2066
|
+
height: '58%',
|
|
2067
|
+
borderRadius: '50%',
|
|
2068
|
+
backgroundColor: '#2e7d32',
|
|
2069
|
+
display: 'flex',
|
|
2070
|
+
alignItems: 'center',
|
|
2071
|
+
justifyContent: 'center',
|
|
2072
|
+
boxShadow: '0 4px 20px rgba(0, 0, 0, 0.4)',
|
|
2073
|
+
};
|
|
2074
|
+
/** Large green check centered over the full chessboard when a line completes. */
|
|
2075
|
+
const BoardCompleteCheckOverlay = () => (jsx("div", { "aria-hidden": true, style: overlayStyle$1, children: jsx("span", { style: badgeStyle, children: jsx("svg", { viewBox: "0 0 24 24", width: "58%", height: "58%", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: jsx("path", { d: "M5 13l4 4L19 7", stroke: "#fff", strokeWidth: "3", strokeLinecap: "round", strokeLinejoin: "round" }) }) }) }));
|
|
2076
|
+
|
|
2018
2077
|
const emptyEngineEvaluation = () => ({
|
|
2019
2078
|
status: 'idle',
|
|
2020
2079
|
depth: 0,
|
|
@@ -3712,20 +3771,25 @@ function evaluateExpectedMoveDrop(fen, sourceSquare, targetSquare, piece, expect
|
|
|
3712
3771
|
if (!uci) {
|
|
3713
3772
|
return { kind: 'illegal' };
|
|
3714
3773
|
}
|
|
3774
|
+
const attempt = {
|
|
3775
|
+
uci,
|
|
3776
|
+
sourceSquare,
|
|
3777
|
+
targetSquare,
|
|
3778
|
+
};
|
|
3715
3779
|
if (matchesExpectedUci(uci, expectedUci)) {
|
|
3716
|
-
return { kind: 'correct',
|
|
3780
|
+
return { kind: 'correct', attempt };
|
|
3717
3781
|
}
|
|
3718
|
-
return { kind: 'incorrect',
|
|
3782
|
+
return { kind: 'incorrect', attempt };
|
|
3719
3783
|
}
|
|
3720
3784
|
function createExpectedMoveDropHandler({ fen, expectedUci, enabled, onCorrect, onIncorrect, }) {
|
|
3721
3785
|
return (sourceSquare, targetSquare, piece) => {
|
|
3722
3786
|
const result = evaluateExpectedMoveDrop(fen, sourceSquare, targetSquare, piece, expectedUci, enabled);
|
|
3723
3787
|
switch (result.kind) {
|
|
3724
3788
|
case 'correct':
|
|
3725
|
-
onCorrect(result.
|
|
3789
|
+
onCorrect(result.attempt);
|
|
3726
3790
|
return true;
|
|
3727
3791
|
case 'incorrect':
|
|
3728
|
-
onIncorrect(result.
|
|
3792
|
+
onIncorrect(result.attempt);
|
|
3729
3793
|
return false;
|
|
3730
3794
|
default:
|
|
3731
3795
|
return false;
|
|
@@ -3777,6 +3841,69 @@ function useCorrectMoveFeedback(delayMs = CORRECT_MOVE_FEEDBACK_MS) {
|
|
|
3777
3841
|
};
|
|
3778
3842
|
}
|
|
3779
3843
|
|
|
3844
|
+
function useIncorrectMoveFeedback(delayMs = CORRECT_MOVE_FEEDBACK_MS) {
|
|
3845
|
+
const [incorrectMoveSquare, setIncorrectMoveSquare] = useState(null);
|
|
3846
|
+
const timeoutRef = useRef(null);
|
|
3847
|
+
const clearIncorrectMoveFeedback = useCallback(() => {
|
|
3848
|
+
if (timeoutRef.current !== null) {
|
|
3849
|
+
window.clearTimeout(timeoutRef.current);
|
|
3850
|
+
timeoutRef.current = null;
|
|
3851
|
+
}
|
|
3852
|
+
setIncorrectMoveSquare(null);
|
|
3853
|
+
}, []);
|
|
3854
|
+
const showIncorrectMove = useCallback((originSquare, onComplete) => {
|
|
3855
|
+
clearIncorrectMoveFeedback();
|
|
3856
|
+
setIncorrectMoveSquare(originSquare);
|
|
3857
|
+
timeoutRef.current = window.setTimeout(() => {
|
|
3858
|
+
timeoutRef.current = null;
|
|
3859
|
+
setIncorrectMoveSquare(null);
|
|
3860
|
+
onComplete === null || onComplete === void 0 ? void 0 : onComplete();
|
|
3861
|
+
}, delayMs);
|
|
3862
|
+
}, [clearIncorrectMoveFeedback, delayMs]);
|
|
3863
|
+
useEffect(() => clearIncorrectMoveFeedback, [clearIncorrectMoveFeedback]);
|
|
3864
|
+
return {
|
|
3865
|
+
incorrectMoveSquare,
|
|
3866
|
+
showIncorrectMove,
|
|
3867
|
+
clearIncorrectMoveFeedback,
|
|
3868
|
+
isShowingIncorrectMove: incorrectMoveSquare !== null,
|
|
3869
|
+
};
|
|
3870
|
+
}
|
|
3871
|
+
|
|
3872
|
+
/**
|
|
3873
|
+
* Shared correct/incorrect move overlays for training boards.
|
|
3874
|
+
* Incorrect feedback always uses the drag origin square (snapped-back piece).
|
|
3875
|
+
*/
|
|
3876
|
+
function useTrainingMoveFeedback(delayMs) {
|
|
3877
|
+
const { correctMoveSquare, showCorrectMove, clearCorrectMoveFeedback, isShowingCorrectMove, } = useCorrectMoveFeedback(delayMs);
|
|
3878
|
+
const { incorrectMoveSquare, showIncorrectMove, clearIncorrectMoveFeedback, isShowingIncorrectMove, } = useIncorrectMoveFeedback(delayMs);
|
|
3879
|
+
const clearMoveFeedback = useCallback(() => {
|
|
3880
|
+
clearCorrectMoveFeedback();
|
|
3881
|
+
clearIncorrectMoveFeedback();
|
|
3882
|
+
}, [clearCorrectMoveFeedback, clearIncorrectMoveFeedback]);
|
|
3883
|
+
const createDropHandler = useCallback((_a) => {
|
|
3884
|
+
var { onCorrect, onIncorrect } = _a, options = __rest(_a, ["onCorrect", "onIncorrect"]);
|
|
3885
|
+
return createExpectedMoveDropHandler(Object.assign(Object.assign({}, options), { onCorrect: (attempt) => {
|
|
3886
|
+
onCorrect === null || onCorrect === void 0 ? void 0 : onCorrect(attempt);
|
|
3887
|
+
}, onIncorrect: (attempt) => {
|
|
3888
|
+
showIncorrectMove(attempt.sourceSquare);
|
|
3889
|
+
onIncorrect === null || onIncorrect === void 0 ? void 0 : onIncorrect(attempt);
|
|
3890
|
+
} }));
|
|
3891
|
+
}, [showIncorrectMove]);
|
|
3892
|
+
return {
|
|
3893
|
+
correctMoveSquare,
|
|
3894
|
+
incorrectMoveSquare,
|
|
3895
|
+
showCorrectMove,
|
|
3896
|
+
showIncorrectMove,
|
|
3897
|
+
clearMoveFeedback,
|
|
3898
|
+
clearCorrectMoveFeedback,
|
|
3899
|
+
clearIncorrectMoveFeedback,
|
|
3900
|
+
isShowingCorrectMove,
|
|
3901
|
+
isShowingIncorrectMove,
|
|
3902
|
+
isShowingMoveFeedback: isShowingCorrectMove || isShowingIncorrectMove,
|
|
3903
|
+
createDropHandler,
|
|
3904
|
+
};
|
|
3905
|
+
}
|
|
3906
|
+
|
|
3780
3907
|
/** Minimum eval loss (pawns) from the wrong move before showing a refutation. */
|
|
3781
3908
|
const REFUTATION_EVAL_GAP_PAWNS = 0.5;
|
|
3782
3909
|
const REFUTATION_EVAL_GAP_CP = REFUTATION_EVAL_GAP_PAWNS * 100;
|
|
@@ -3879,9 +4006,9 @@ function getMissDisplay(sequence, expectedUci, refutationUci, answerArrowColor)
|
|
|
3879
4006
|
switch (phase) {
|
|
3880
4007
|
case 'wrong':
|
|
3881
4008
|
return {
|
|
3882
|
-
fen:
|
|
4009
|
+
fen: setupFen,
|
|
3883
4010
|
arrows: [],
|
|
3884
|
-
lastMoveUci:
|
|
4011
|
+
lastMoveUci: null,
|
|
3885
4012
|
animating: false,
|
|
3886
4013
|
};
|
|
3887
4014
|
case 'refutation': {
|
|
@@ -4091,4 +4218,4 @@ function useMissBoard({ feedback, expectedUci, positionFen, answerArrowColor, au
|
|
|
4091
4218
|
};
|
|
4092
4219
|
}
|
|
4093
4220
|
|
|
4094
|
-
export { AnalysisBoard, AnalysisBoardCore, AnalysisBoardCoreView, AnalysisBoardLayout, AnalysisChessboardView, AnalysisEngineProvider, AnalysisErrorBoundary, AnalysisPosition, BOARD_THEMES, BOARD_THEME_IDS, CORRECT_MOVE_FEEDBACK_MS, ChessboardDnDProvider, ChessboardThemeContext, CorrectMoveCheckBadge, DEFAULT_ANALYSIS_LAYOUT, DEFAULT_BOARD_THEME, DEFAULT_LAST_MOVE_ARROW_COLOR, DEFAULT_STOCKFISH_SCRIPT_URL, DefaultAnalysisContainer, DefaultAnalysisSidebar, DefaultPlyNavigation, EngineEvaluationPanel, HighlightChessboard, MISS_MOVE_ANIMATION_MS, MISS_REFUTATION_MAX_WAIT_MS, MISS_REFUTATION_PAUSE_MS, MISS_WRONG_PAUSE_MS, PlyNavigation, REFUTATION_EVAL_GAP_CP, REFUTATION_EVAL_GAP_PAWNS, StockfishBrowserEngine, ThemeProvider, analysisBoardHighlightColors, analysisSidebarColors, applyUciMove, boardSquareHighlightColors, boardThemeFromLegacyUiTheme, createExpectedMoveDropHandler, createSidebarRowBandCounters, defaultRenderPlyNavigation, emptyEngineEvaluation, evaluateExpectedMoveDrop, fenAfterUci, formatEvaluation, formatPvPreview, getAnalysisModalStyles, getBoardThemeStyles, getCheckSquareFromChess, getLastMoveSquareStyles, getMissDisplay, getSidebarRowBackground, getStylesForTheme, isAnalyzableFen, isBoardThemeId, isEditableKeyboardTarget, lastMoveArrowFromUci, lastMoveUciAtPly, lineEvalCpForGap, matchesExpectedUci, mergeCustomArrowsWithLastMove, navButtonStyle, navRowStyle, normalizeEvalForWhite, normalizePvMoves, normalizeSubscriberOptions, parseUciInfoLine, parseUciMove, plyLabelStyle, palette as plyNavigationPalette, refutationEngineOptions, refutationEvalGapCp, refutationFromEvaluation, resolveStockfishScriptUrl, resolveStockfishWasmUrl, resolveStockfishWorkerUrl, scrubberInputStyle, splitWorkerLines, uciFromDrop, uciPvToSan, uciToArrow, useAnalysisBoardModel, useAnalysisEngine, useAnalysisEngineContext, useBoardRevision, useChessboardTheme, useCorrectMoveFeedback, useMissBoard, useMissRefutation, useMissSequence, usePositionKeyboardNav, useTheme };
|
|
4221
|
+
export { AnalysisBoard, AnalysisBoardCore, AnalysisBoardCoreView, AnalysisBoardLayout, AnalysisChessboardView, AnalysisEngineProvider, AnalysisErrorBoundary, AnalysisPosition, BOARD_THEMES, BOARD_THEME_IDS, BoardCompleteCheckOverlay, CORRECT_MOVE_FEEDBACK_MS, ChessboardDnDProvider, ChessboardThemeContext, CorrectMoveCheckBadge, DEFAULT_ANALYSIS_LAYOUT, DEFAULT_ANSWER_ARROW_COLOR, DEFAULT_BOARD_THEME, DEFAULT_LAST_MOVE_ARROW_COLOR, DEFAULT_STOCKFISH_SCRIPT_URL, DefaultAnalysisContainer, DefaultAnalysisSidebar, DefaultPlyNavigation, EngineEvaluationPanel, HighlightChessboard, IncorrectMoveXBadge, MISS_MOVE_ANIMATION_MS, MISS_REFUTATION_MAX_WAIT_MS, MISS_REFUTATION_PAUSE_MS, MISS_WRONG_PAUSE_MS, PlyNavigation, REFUTATION_EVAL_GAP_CP, REFUTATION_EVAL_GAP_PAWNS, StockfishBrowserEngine, ThemeProvider, analysisBoardHighlightColors, analysisSidebarColors, applyUciMove, boardArrowColors, boardSquareHighlightColors, boardThemeFromLegacyUiTheme, createExpectedMoveDropHandler, createSidebarRowBandCounters, defaultRenderPlyNavigation, emptyEngineEvaluation, evaluateExpectedMoveDrop, fenAfterUci, formatEvaluation, formatPvPreview, getAnalysisModalStyles, getBoardThemeStyles, getCheckSquareFromChess, getLastMoveSquareStyles, getMissDisplay, getSidebarRowBackground, getStylesForTheme, isAnalyzableFen, isBoardThemeId, isEditableKeyboardTarget, lastMoveArrowFromUci, lastMoveUciAtPly, lineEvalCpForGap, matchesExpectedUci, mergeCustomArrowsWithLastMove, navButtonStyle, navRowStyle, normalizeEvalForWhite, normalizePvMoves, normalizeSubscriberOptions, parseUciInfoLine, parseUciMove, plyLabelStyle, palette as plyNavigationPalette, refutationEngineOptions, refutationEvalGapCp, refutationFromEvaluation, resolveStockfishScriptUrl, resolveStockfishWasmUrl, resolveStockfishWorkerUrl, scrubberInputStyle, splitWorkerLines, uciFromDrop, uciPvToSan, uciToArrow, useAnalysisBoardModel, useAnalysisEngine, useAnalysisEngineContext, useBoardRevision, useChessboardTheme, useCorrectMoveFeedback, useIncorrectMoveFeedback, useMissBoard, useMissRefutation, useMissSequence, usePositionKeyboardNav, useTheme, useTrainingMoveFeedback };
|
package/dist/index.js
CHANGED
|
@@ -1748,7 +1748,7 @@ const boardSquareHighlightColors = {
|
|
|
1748
1748
|
captureTarget: 'radial-gradient(circle, rgba(0, 0, 0, 0.18) 72%, transparent 72%)',
|
|
1749
1749
|
};
|
|
1750
1750
|
|
|
1751
|
-
const badgeStyle = {
|
|
1751
|
+
const badgeStyle$2 = {
|
|
1752
1752
|
position: 'absolute',
|
|
1753
1753
|
right: '6%',
|
|
1754
1754
|
bottom: '6%',
|
|
@@ -1768,29 +1768,69 @@ const badgeStyle = {
|
|
|
1768
1768
|
};
|
|
1769
1769
|
/** Green circle with a white check, anchored to the bottom-right of a square
|
|
1770
1770
|
* square (over the piece). */
|
|
1771
|
-
const CorrectMoveCheckBadge = () => (jsxRuntime.jsx("span", { "aria-hidden": true, style: badgeStyle, children: jsxRuntime.jsx("svg", { viewBox: "0 0 12 12", width: "62%", height: "62%", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: jsxRuntime.jsx("path", { d: "M2.5 6.2 5 8.7 9.5 3.8", stroke: "#fff", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round" }) }) }));
|
|
1771
|
+
const CorrectMoveCheckBadge = () => (jsxRuntime.jsx("span", { "aria-hidden": true, style: badgeStyle$2, children: jsxRuntime.jsx("svg", { viewBox: "0 0 12 12", width: "62%", height: "62%", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: jsxRuntime.jsx("path", { d: "M2.5 6.2 5 8.7 9.5 3.8", stroke: "#fff", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round" }) }) }));
|
|
1772
1772
|
|
|
1773
|
-
const
|
|
1773
|
+
const badgeStyle$1 = {
|
|
1774
|
+
position: 'absolute',
|
|
1775
|
+
right: '6%',
|
|
1776
|
+
bottom: '6%',
|
|
1777
|
+
width: '26%',
|
|
1778
|
+
height: '26%',
|
|
1779
|
+
minWidth: 14,
|
|
1780
|
+
minHeight: 14,
|
|
1781
|
+
maxWidth: 26,
|
|
1782
|
+
maxHeight: 26,
|
|
1783
|
+
borderRadius: '50%',
|
|
1784
|
+
backgroundColor: '#c62828',
|
|
1785
|
+
display: 'flex',
|
|
1786
|
+
alignItems: 'center',
|
|
1787
|
+
justifyContent: 'center',
|
|
1788
|
+
boxShadow: '0 1px 3px rgba(0, 0, 0, 0.35)',
|
|
1789
|
+
pointerEvents: 'none',
|
|
1790
|
+
};
|
|
1791
|
+
/** Red circle with a white X, anchored to the bottom-right of a square. */
|
|
1792
|
+
const IncorrectMoveXBadge = () => (jsxRuntime.jsx("span", { "aria-hidden": true, style: badgeStyle$1, children: jsxRuntime.jsx("svg", { viewBox: "0 0 12 12", width: "58%", height: "58%", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: jsxRuntime.jsx("path", { d: "M3.2 3.2 8.8 8.8M8.8 3.2 3.2 8.8", stroke: "#fff", strokeWidth: "1.8", strokeLinecap: "round" }) }) }));
|
|
1793
|
+
|
|
1794
|
+
const overlayStyle$2 = {
|
|
1774
1795
|
position: 'absolute',
|
|
1775
1796
|
inset: 0,
|
|
1776
1797
|
pointerEvents: 'none',
|
|
1777
1798
|
zIndex: 20,
|
|
1778
1799
|
overflow: 'visible',
|
|
1779
1800
|
};
|
|
1780
|
-
function createFeedbackSquareRenderer(correctMoveSquare) {
|
|
1801
|
+
function createFeedbackSquareRenderer({ correctMoveSquare = null, incorrectMoveSquare = null, }) {
|
|
1802
|
+
if (!correctMoveSquare && !incorrectMoveSquare) {
|
|
1803
|
+
return undefined;
|
|
1804
|
+
}
|
|
1781
1805
|
return function FeedbackSquare({ children, style, square, ref }) {
|
|
1782
|
-
return (jsxRuntime.jsxs("div", { ref: ref, style: Object.assign(Object.assign({}, style), { position: 'relative', overflow: 'visible' }), children: [children, square === correctMoveSquare ? (jsxRuntime.jsx("div", { style: overlayStyle$
|
|
1806
|
+
return (jsxRuntime.jsxs("div", { ref: ref, style: Object.assign(Object.assign({}, style), { position: 'relative', overflow: 'visible' }), children: [children, square === correctMoveSquare ? (jsxRuntime.jsx("div", { style: overlayStyle$2, children: jsxRuntime.jsx(CorrectMoveCheckBadge, {}) })) : null, square === incorrectMoveSquare ? (jsxRuntime.jsx("div", { style: overlayStyle$2, children: jsxRuntime.jsx(IncorrectMoveXBadge, {}) })) : null] }));
|
|
1783
1807
|
};
|
|
1784
1808
|
}
|
|
1785
1809
|
|
|
1786
|
-
/**
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
const
|
|
1810
|
+
/**
|
|
1811
|
+
* Board arrow colors — change these values to update arrows app-wide.
|
|
1812
|
+
*/
|
|
1813
|
+
const boardArrowColors = {
|
|
1814
|
+
/** Arrow showing the move that reached the current position. */
|
|
1815
|
+
lastMove: 'rgba(130, 130, 130, 0.75)',
|
|
1816
|
+
/** Arrow showing the correct / answer move during training. */
|
|
1817
|
+
answer: '#1976d2',
|
|
1818
|
+
};
|
|
1819
|
+
/** @deprecated Use {@link boardArrowColors.lastMove} */
|
|
1820
|
+
const DEFAULT_LAST_MOVE_ARROW_COLOR = boardArrowColors.lastMove;
|
|
1821
|
+
/** @deprecated Use {@link boardArrowColors.answer} */
|
|
1822
|
+
const DEFAULT_ANSWER_ARROW_COLOR = boardArrowColors.answer;
|
|
1823
|
+
|
|
1824
|
+
const uciToArrow = (uci) => [
|
|
1825
|
+
uci.slice(0, 2),
|
|
1826
|
+
uci.slice(2, 4),
|
|
1827
|
+
boardArrowColors.lastMove,
|
|
1828
|
+
];
|
|
1829
|
+
const lastMoveArrowFromUci = (uci) => {
|
|
1790
1830
|
if (!uci || uci.length < 4) {
|
|
1791
1831
|
return [];
|
|
1792
1832
|
}
|
|
1793
|
-
return [uciToArrow(uci
|
|
1833
|
+
return [uciToArrow(uci)];
|
|
1794
1834
|
};
|
|
1795
1835
|
/** UCI of the move that produced the position at {@link plyIndex}. */
|
|
1796
1836
|
const lastMoveUciAtPly = (movesUci, plyIndex) => {
|
|
@@ -1800,8 +1840,8 @@ const lastMoveUciAtPly = (movesUci, plyIndex) => {
|
|
|
1800
1840
|
}
|
|
1801
1841
|
return (_a = movesUci[plyIndex - 1]) !== null && _a !== void 0 ? _a : null;
|
|
1802
1842
|
};
|
|
1803
|
-
const mergeCustomArrowsWithLastMove = (customArrows, lastMoveUci
|
|
1804
|
-
const lastMove = lastMoveArrowFromUci(lastMoveUci
|
|
1843
|
+
const mergeCustomArrowsWithLastMove = (customArrows, lastMoveUci) => {
|
|
1844
|
+
const lastMove = lastMoveArrowFromUci(lastMoveUci);
|
|
1805
1845
|
if (!lastMove.length) {
|
|
1806
1846
|
return customArrows !== null && customArrows !== void 0 ? customArrows : [];
|
|
1807
1847
|
}
|
|
@@ -1967,20 +2007,15 @@ const getCheckHighlighting = (checkSquare) => {
|
|
|
1967
2007
|
styles[checkSquare] = { backgroundColor: boardSquareHighlightColors.check };
|
|
1968
2008
|
return styles;
|
|
1969
2009
|
};
|
|
1970
|
-
const getFeedbackHighlighting = (hintSquare
|
|
2010
|
+
const getFeedbackHighlighting = (hintSquare) => {
|
|
1971
2011
|
const styles = {};
|
|
1972
2012
|
if (hintSquare) {
|
|
1973
2013
|
styles[hintSquare] = { backgroundColor: boardSquareHighlightColors.hint };
|
|
1974
2014
|
}
|
|
1975
|
-
if (incorrectMoveSquare) {
|
|
1976
|
-
styles[incorrectMoveSquare] = {
|
|
1977
|
-
backgroundColor: boardSquareHighlightColors.incorrect,
|
|
1978
|
-
};
|
|
1979
|
-
}
|
|
1980
2015
|
return styles;
|
|
1981
2016
|
};
|
|
1982
2017
|
const HighlightChessboard = (_a) => {
|
|
1983
|
-
var { checkSquare, hintSquare, incorrectMoveSquare, correctMoveSquare = null, lastMoveUci = null,
|
|
2018
|
+
var { checkSquare, hintSquare, incorrectMoveSquare = null, correctMoveSquare = null, lastMoveUci = null, clickToMove, customSquareStyles: extraSquareStyles, customArrows, customBoardStyle, onPieceDrop, position, arePiecesDraggable, autoPromoteToQueen, isDraggablePiece, onPromotionCheck, onSquareClick, onPromotionPieceSelect, onPieceDragBegin, showPromotionDialog: showPromotionDialogProp, promotionToSquare: promotionToSquareProp } = _a, props = __rest(_a, ["checkSquare", "hintSquare", "incorrectMoveSquare", "correctMoveSquare", "lastMoveUci", "clickToMove", "customSquareStyles", "customArrows", "customBoardStyle", "onPieceDrop", "position", "arePiecesDraggable", "autoPromoteToQueen", "isDraggablePiece", "onPromotionCheck", "onSquareClick", "onPromotionPieceSelect", "onPieceDragBegin", "showPromotionDialog", "promotionToSquare"]);
|
|
1984
2019
|
const { customDarkSquareStyle, customLightSquareStyle } = useChessboardTheme();
|
|
1985
2020
|
const clickToMoveEnabled = clickToMove !== false && typeof onPieceDrop === 'function';
|
|
1986
2021
|
const { clickSquareStyles, handleSquareClick, handlePromotionPieceSelect, handlePieceDragBegin, showPromotionDialog: clickPromotionDialog, promotionToSquare: clickPromotionToSquare, } = useClickToMove({
|
|
@@ -1996,12 +2031,13 @@ const HighlightChessboard = (_a) => {
|
|
|
1996
2031
|
onPieceDragBegin,
|
|
1997
2032
|
});
|
|
1998
2033
|
const checkStyles = getCheckHighlighting(checkSquare);
|
|
1999
|
-
const feedbackStyles = getFeedbackHighlighting(hintSquare
|
|
2034
|
+
const feedbackStyles = getFeedbackHighlighting(hintSquare);
|
|
2000
2035
|
const customSquareStyles = Object.assign(Object.assign(Object.assign(Object.assign({}, clickSquareStyles), checkStyles), feedbackStyles), extraSquareStyles);
|
|
2001
|
-
const customSquare = react.useMemo(() =>
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2036
|
+
const customSquare = react.useMemo(() => createFeedbackSquareRenderer({
|
|
2037
|
+
correctMoveSquare,
|
|
2038
|
+
incorrectMoveSquare,
|
|
2039
|
+
}), [correctMoveSquare, incorrectMoveSquare]);
|
|
2040
|
+
const mergedCustomArrows = react.useMemo(() => mergeCustomArrowsWithLastMove(customArrows, lastMoveUci), [customArrows, lastMoveUci]);
|
|
2005
2041
|
const promotionControlProps = clickPromotionDialog
|
|
2006
2042
|
? {
|
|
2007
2043
|
showPromotionDialog: true,
|
|
@@ -2017,6 +2053,29 @@ const HighlightChessboard = (_a) => {
|
|
|
2017
2053
|
return (jsxRuntime.jsx(reactChessboard.Chessboard, Object.assign({ customDarkSquareStyle: customDarkSquareStyle, customLightSquareStyle: customLightSquareStyle, customSquareStyles: customSquareStyles, customSquare: customSquare, customBoardStyle: Object.assign(Object.assign({}, nonSelectableBoardStyle), customBoardStyle), position: position, arePiecesDraggable: arePiecesDraggable, autoPromoteToQueen: autoPromoteToQueen, isDraggablePiece: isDraggablePiece, onPromotionCheck: onPromotionCheck, onPieceDrop: onPieceDrop, onSquareClick: clickToMoveEnabled ? handleSquareClick : onSquareClick, onPromotionPieceSelect: clickToMoveEnabled ? handlePromotionPieceSelect : onPromotionPieceSelect, onPieceDragBegin: clickToMoveEnabled ? handlePieceDragBegin : onPieceDragBegin, customArrows: mergedCustomArrows }, promotionControlProps, props)));
|
|
2018
2054
|
};
|
|
2019
2055
|
|
|
2056
|
+
const overlayStyle$1 = {
|
|
2057
|
+
position: 'absolute',
|
|
2058
|
+
inset: 0,
|
|
2059
|
+
display: 'flex',
|
|
2060
|
+
alignItems: 'center',
|
|
2061
|
+
justifyContent: 'center',
|
|
2062
|
+
pointerEvents: 'none',
|
|
2063
|
+
zIndex: 10,
|
|
2064
|
+
borderRadius: 4,
|
|
2065
|
+
};
|
|
2066
|
+
const badgeStyle = {
|
|
2067
|
+
width: '58%',
|
|
2068
|
+
height: '58%',
|
|
2069
|
+
borderRadius: '50%',
|
|
2070
|
+
backgroundColor: '#2e7d32',
|
|
2071
|
+
display: 'flex',
|
|
2072
|
+
alignItems: 'center',
|
|
2073
|
+
justifyContent: 'center',
|
|
2074
|
+
boxShadow: '0 4px 20px rgba(0, 0, 0, 0.4)',
|
|
2075
|
+
};
|
|
2076
|
+
/** Large green check centered over the full chessboard when a line completes. */
|
|
2077
|
+
const BoardCompleteCheckOverlay = () => (jsxRuntime.jsx("div", { "aria-hidden": true, style: overlayStyle$1, children: jsxRuntime.jsx("span", { style: badgeStyle, children: jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", width: "58%", height: "58%", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: jsxRuntime.jsx("path", { d: "M5 13l4 4L19 7", stroke: "#fff", strokeWidth: "3", strokeLinecap: "round", strokeLinejoin: "round" }) }) }) }));
|
|
2078
|
+
|
|
2020
2079
|
const emptyEngineEvaluation = () => ({
|
|
2021
2080
|
status: 'idle',
|
|
2022
2081
|
depth: 0,
|
|
@@ -3714,20 +3773,25 @@ function evaluateExpectedMoveDrop(fen, sourceSquare, targetSquare, piece, expect
|
|
|
3714
3773
|
if (!uci) {
|
|
3715
3774
|
return { kind: 'illegal' };
|
|
3716
3775
|
}
|
|
3776
|
+
const attempt = {
|
|
3777
|
+
uci,
|
|
3778
|
+
sourceSquare,
|
|
3779
|
+
targetSquare,
|
|
3780
|
+
};
|
|
3717
3781
|
if (matchesExpectedUci(uci, expectedUci)) {
|
|
3718
|
-
return { kind: 'correct',
|
|
3782
|
+
return { kind: 'correct', attempt };
|
|
3719
3783
|
}
|
|
3720
|
-
return { kind: 'incorrect',
|
|
3784
|
+
return { kind: 'incorrect', attempt };
|
|
3721
3785
|
}
|
|
3722
3786
|
function createExpectedMoveDropHandler({ fen, expectedUci, enabled, onCorrect, onIncorrect, }) {
|
|
3723
3787
|
return (sourceSquare, targetSquare, piece) => {
|
|
3724
3788
|
const result = evaluateExpectedMoveDrop(fen, sourceSquare, targetSquare, piece, expectedUci, enabled);
|
|
3725
3789
|
switch (result.kind) {
|
|
3726
3790
|
case 'correct':
|
|
3727
|
-
onCorrect(result.
|
|
3791
|
+
onCorrect(result.attempt);
|
|
3728
3792
|
return true;
|
|
3729
3793
|
case 'incorrect':
|
|
3730
|
-
onIncorrect(result.
|
|
3794
|
+
onIncorrect(result.attempt);
|
|
3731
3795
|
return false;
|
|
3732
3796
|
default:
|
|
3733
3797
|
return false;
|
|
@@ -3779,6 +3843,69 @@ function useCorrectMoveFeedback(delayMs = CORRECT_MOVE_FEEDBACK_MS) {
|
|
|
3779
3843
|
};
|
|
3780
3844
|
}
|
|
3781
3845
|
|
|
3846
|
+
function useIncorrectMoveFeedback(delayMs = CORRECT_MOVE_FEEDBACK_MS) {
|
|
3847
|
+
const [incorrectMoveSquare, setIncorrectMoveSquare] = react.useState(null);
|
|
3848
|
+
const timeoutRef = react.useRef(null);
|
|
3849
|
+
const clearIncorrectMoveFeedback = react.useCallback(() => {
|
|
3850
|
+
if (timeoutRef.current !== null) {
|
|
3851
|
+
window.clearTimeout(timeoutRef.current);
|
|
3852
|
+
timeoutRef.current = null;
|
|
3853
|
+
}
|
|
3854
|
+
setIncorrectMoveSquare(null);
|
|
3855
|
+
}, []);
|
|
3856
|
+
const showIncorrectMove = react.useCallback((originSquare, onComplete) => {
|
|
3857
|
+
clearIncorrectMoveFeedback();
|
|
3858
|
+
setIncorrectMoveSquare(originSquare);
|
|
3859
|
+
timeoutRef.current = window.setTimeout(() => {
|
|
3860
|
+
timeoutRef.current = null;
|
|
3861
|
+
setIncorrectMoveSquare(null);
|
|
3862
|
+
onComplete === null || onComplete === void 0 ? void 0 : onComplete();
|
|
3863
|
+
}, delayMs);
|
|
3864
|
+
}, [clearIncorrectMoveFeedback, delayMs]);
|
|
3865
|
+
react.useEffect(() => clearIncorrectMoveFeedback, [clearIncorrectMoveFeedback]);
|
|
3866
|
+
return {
|
|
3867
|
+
incorrectMoveSquare,
|
|
3868
|
+
showIncorrectMove,
|
|
3869
|
+
clearIncorrectMoveFeedback,
|
|
3870
|
+
isShowingIncorrectMove: incorrectMoveSquare !== null,
|
|
3871
|
+
};
|
|
3872
|
+
}
|
|
3873
|
+
|
|
3874
|
+
/**
|
|
3875
|
+
* Shared correct/incorrect move overlays for training boards.
|
|
3876
|
+
* Incorrect feedback always uses the drag origin square (snapped-back piece).
|
|
3877
|
+
*/
|
|
3878
|
+
function useTrainingMoveFeedback(delayMs) {
|
|
3879
|
+
const { correctMoveSquare, showCorrectMove, clearCorrectMoveFeedback, isShowingCorrectMove, } = useCorrectMoveFeedback(delayMs);
|
|
3880
|
+
const { incorrectMoveSquare, showIncorrectMove, clearIncorrectMoveFeedback, isShowingIncorrectMove, } = useIncorrectMoveFeedback(delayMs);
|
|
3881
|
+
const clearMoveFeedback = react.useCallback(() => {
|
|
3882
|
+
clearCorrectMoveFeedback();
|
|
3883
|
+
clearIncorrectMoveFeedback();
|
|
3884
|
+
}, [clearCorrectMoveFeedback, clearIncorrectMoveFeedback]);
|
|
3885
|
+
const createDropHandler = react.useCallback((_a) => {
|
|
3886
|
+
var { onCorrect, onIncorrect } = _a, options = __rest(_a, ["onCorrect", "onIncorrect"]);
|
|
3887
|
+
return createExpectedMoveDropHandler(Object.assign(Object.assign({}, options), { onCorrect: (attempt) => {
|
|
3888
|
+
onCorrect === null || onCorrect === void 0 ? void 0 : onCorrect(attempt);
|
|
3889
|
+
}, onIncorrect: (attempt) => {
|
|
3890
|
+
showIncorrectMove(attempt.sourceSquare);
|
|
3891
|
+
onIncorrect === null || onIncorrect === void 0 ? void 0 : onIncorrect(attempt);
|
|
3892
|
+
} }));
|
|
3893
|
+
}, [showIncorrectMove]);
|
|
3894
|
+
return {
|
|
3895
|
+
correctMoveSquare,
|
|
3896
|
+
incorrectMoveSquare,
|
|
3897
|
+
showCorrectMove,
|
|
3898
|
+
showIncorrectMove,
|
|
3899
|
+
clearMoveFeedback,
|
|
3900
|
+
clearCorrectMoveFeedback,
|
|
3901
|
+
clearIncorrectMoveFeedback,
|
|
3902
|
+
isShowingCorrectMove,
|
|
3903
|
+
isShowingIncorrectMove,
|
|
3904
|
+
isShowingMoveFeedback: isShowingCorrectMove || isShowingIncorrectMove,
|
|
3905
|
+
createDropHandler,
|
|
3906
|
+
};
|
|
3907
|
+
}
|
|
3908
|
+
|
|
3782
3909
|
/** Minimum eval loss (pawns) from the wrong move before showing a refutation. */
|
|
3783
3910
|
const REFUTATION_EVAL_GAP_PAWNS = 0.5;
|
|
3784
3911
|
const REFUTATION_EVAL_GAP_CP = REFUTATION_EVAL_GAP_PAWNS * 100;
|
|
@@ -3881,9 +4008,9 @@ function getMissDisplay(sequence, expectedUci, refutationUci, answerArrowColor)
|
|
|
3881
4008
|
switch (phase) {
|
|
3882
4009
|
case 'wrong':
|
|
3883
4010
|
return {
|
|
3884
|
-
fen:
|
|
4011
|
+
fen: setupFen,
|
|
3885
4012
|
arrows: [],
|
|
3886
|
-
lastMoveUci:
|
|
4013
|
+
lastMoveUci: null,
|
|
3887
4014
|
animating: false,
|
|
3888
4015
|
};
|
|
3889
4016
|
case 'refutation': {
|
|
@@ -4103,11 +4230,13 @@ exports.AnalysisErrorBoundary = AnalysisErrorBoundary;
|
|
|
4103
4230
|
exports.AnalysisPosition = AnalysisPosition;
|
|
4104
4231
|
exports.BOARD_THEMES = BOARD_THEMES;
|
|
4105
4232
|
exports.BOARD_THEME_IDS = BOARD_THEME_IDS;
|
|
4233
|
+
exports.BoardCompleteCheckOverlay = BoardCompleteCheckOverlay;
|
|
4106
4234
|
exports.CORRECT_MOVE_FEEDBACK_MS = CORRECT_MOVE_FEEDBACK_MS;
|
|
4107
4235
|
exports.ChessboardDnDProvider = ChessboardDnDProvider;
|
|
4108
4236
|
exports.ChessboardThemeContext = ChessboardThemeContext;
|
|
4109
4237
|
exports.CorrectMoveCheckBadge = CorrectMoveCheckBadge;
|
|
4110
4238
|
exports.DEFAULT_ANALYSIS_LAYOUT = DEFAULT_ANALYSIS_LAYOUT;
|
|
4239
|
+
exports.DEFAULT_ANSWER_ARROW_COLOR = DEFAULT_ANSWER_ARROW_COLOR;
|
|
4111
4240
|
exports.DEFAULT_BOARD_THEME = DEFAULT_BOARD_THEME;
|
|
4112
4241
|
exports.DEFAULT_LAST_MOVE_ARROW_COLOR = DEFAULT_LAST_MOVE_ARROW_COLOR;
|
|
4113
4242
|
exports.DEFAULT_STOCKFISH_SCRIPT_URL = DEFAULT_STOCKFISH_SCRIPT_URL;
|
|
@@ -4116,6 +4245,7 @@ exports.DefaultAnalysisSidebar = DefaultAnalysisSidebar;
|
|
|
4116
4245
|
exports.DefaultPlyNavigation = DefaultPlyNavigation;
|
|
4117
4246
|
exports.EngineEvaluationPanel = EngineEvaluationPanel;
|
|
4118
4247
|
exports.HighlightChessboard = HighlightChessboard;
|
|
4248
|
+
exports.IncorrectMoveXBadge = IncorrectMoveXBadge;
|
|
4119
4249
|
exports.MISS_MOVE_ANIMATION_MS = MISS_MOVE_ANIMATION_MS;
|
|
4120
4250
|
exports.MISS_REFUTATION_MAX_WAIT_MS = MISS_REFUTATION_MAX_WAIT_MS;
|
|
4121
4251
|
exports.MISS_REFUTATION_PAUSE_MS = MISS_REFUTATION_PAUSE_MS;
|
|
@@ -4128,6 +4258,7 @@ exports.ThemeProvider = ThemeProvider;
|
|
|
4128
4258
|
exports.analysisBoardHighlightColors = analysisBoardHighlightColors;
|
|
4129
4259
|
exports.analysisSidebarColors = analysisSidebarColors;
|
|
4130
4260
|
exports.applyUciMove = applyUciMove;
|
|
4261
|
+
exports.boardArrowColors = boardArrowColors;
|
|
4131
4262
|
exports.boardSquareHighlightColors = boardSquareHighlightColors;
|
|
4132
4263
|
exports.boardThemeFromLegacyUiTheme = boardThemeFromLegacyUiTheme;
|
|
4133
4264
|
exports.createExpectedMoveDropHandler = createExpectedMoveDropHandler;
|
|
@@ -4179,8 +4310,10 @@ exports.useAnalysisEngineContext = useAnalysisEngineContext;
|
|
|
4179
4310
|
exports.useBoardRevision = useBoardRevision;
|
|
4180
4311
|
exports.useChessboardTheme = useChessboardTheme;
|
|
4181
4312
|
exports.useCorrectMoveFeedback = useCorrectMoveFeedback;
|
|
4313
|
+
exports.useIncorrectMoveFeedback = useIncorrectMoveFeedback;
|
|
4182
4314
|
exports.useMissBoard = useMissBoard;
|
|
4183
4315
|
exports.useMissRefutation = useMissRefutation;
|
|
4184
4316
|
exports.useMissSequence = useMissSequence;
|
|
4185
4317
|
exports.usePositionKeyboardNav = usePositionKeyboardNav;
|
|
4186
4318
|
exports.useTheme = useTheme;
|
|
4319
|
+
exports.useTrainingMoveFeedback = useTrainingMoveFeedback;
|