react-chess-explorer 0.0.3 → 0.0.5
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/LICENSE +21 -21
- package/README.md +65 -63
- package/dist/features/explorer/hooks/useGameReplayTraining.d.ts +1 -0
- package/dist/features/explorer/hooks/usePositionHistory.d.ts +6 -1
- package/dist/features/explorer/hooks/usePositionReferenceData.d.ts +1 -0
- package/dist/features/explorer/positionUtils.d.ts +1 -0
- package/dist/index.esm.js +49 -24
- package/dist/index.js +48 -23
- package/package.json +59 -59
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 Robert Blackwell
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Robert Blackwell
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,63 +1,65 @@
|
|
|
1
|
-
# react-chess-explorer
|
|
2
|
-
|
|
3
|
-
```bash
|
|
4
|
-
npm install
|
|
5
|
-
npm run build
|
|
6
|
-
```
|
|
7
|
-
|
|
8
|
-
React components for **browsing and replaying chess games**. This package depends on **`react-chess-core` only** (board + engine primitives), not `react-chess-puzzle-kit`.
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
cd ../react-chess-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
1
|
+
# react-chess-explorer
|
|
2
|
+
|
|
3
|
+
```bash
|
|
4
|
+
npm install
|
|
5
|
+
npm run build
|
|
6
|
+
```
|
|
7
|
+
|
|
8
|
+
React components for **browsing and replaying chess games**. This package depends on **`react-chess-core` only** (board + engine primitives), not `react-chess-puzzle-kit`.
|
|
9
|
+
|
|
10
|
+
Used in production at [endchess.com](https://endchess.com).
|
|
11
|
+
|
|
12
|
+
**Status:** Phase 5 scaffold — paste requirements into `docs/REQUIREMENTS.md` (or issue) before implementing replay UI.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Local setup
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
# Build core first
|
|
20
|
+
cd ../react-chess-core && npm run build
|
|
21
|
+
|
|
22
|
+
cd ../react-chess-explorer
|
|
23
|
+
npm install
|
|
24
|
+
npm run build
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
**Peer dependencies:** `react`, `react-chessboard`, `chess.js`, **`react-chess-core`**
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
npm install react-chess-explorer react-chess-core
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Exports (scaffold)
|
|
36
|
+
|
|
37
|
+
| Export | Role |
|
|
38
|
+
|--------|------|
|
|
39
|
+
| **`ExplorerPlaceholder`** | Themed board at start position + scaffold label |
|
|
40
|
+
| **`EXPLORER_START_FEN`** | Default FEN constant |
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Requirements
|
|
45
|
+
|
|
46
|
+
Add product/API requirements here when ready:
|
|
47
|
+
|
|
48
|
+
- `docs/REQUIREMENTS.md` (create when you paste the doc)
|
|
49
|
+
|
|
50
|
+
Planned scope (from migration plan): move list, ply navigation, optional engine — wired to EndChess `/games` routes.
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Related packages
|
|
55
|
+
|
|
56
|
+
| Package | Role |
|
|
57
|
+
|---------|------|
|
|
58
|
+
| [react-chess-core](https://github.com/reblackwell3/react-chess-core) | Board theme, highlights, Stockfish |
|
|
59
|
+
| [react-chess-puzzle-kit](https://github.com/reblackwell3/react-chess-puzzle-kit) | Puzzles (separate; not a dependency) |
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## License
|
|
64
|
+
|
|
65
|
+
MIT © Robert Blackwell
|
|
@@ -16,6 +16,7 @@ export declare function useGameReplayTraining({ gameId, startFen, fetchGame, }:
|
|
|
16
16
|
error: string | null;
|
|
17
17
|
feedback: GameReplayFeedback;
|
|
18
18
|
lastExpectedSan: string | null;
|
|
19
|
+
lastMoveUci: any;
|
|
19
20
|
expectedSan: string | undefined;
|
|
20
21
|
handlePieceDrop: (sourceSquare: string, targetSquare: string, piece: string) => boolean;
|
|
21
22
|
revealMove: () => void;
|
|
@@ -2,6 +2,8 @@ export type PositionHistoryEntry = {
|
|
|
2
2
|
fen: string;
|
|
3
3
|
/** SAN of the move played from the previous entry to reach this FEN. */
|
|
4
4
|
lastSan?: string;
|
|
5
|
+
/** UCI of the move played from the previous entry to reach this FEN. */
|
|
6
|
+
lastUci?: string;
|
|
5
7
|
};
|
|
6
8
|
export declare function initialHistoryState(initialFen: string, initialLineSans?: string[]): {
|
|
7
9
|
history: PositionHistoryEntry[];
|
|
@@ -13,14 +15,17 @@ export declare function usePositionHistory(initialFen: string, initialLineSans?:
|
|
|
13
15
|
lineSans: string[];
|
|
14
16
|
forwardSans: string[];
|
|
15
17
|
currentFen: string;
|
|
16
|
-
|
|
18
|
+
lastMoveUci: string | null;
|
|
19
|
+
pushEntry: (fen: string, lastSan?: string, lastUci?: string) => PositionHistoryEntry;
|
|
17
20
|
pushEntries: (entries: {
|
|
18
21
|
fen: string;
|
|
19
22
|
lastSan: string;
|
|
23
|
+
lastUci?: string;
|
|
20
24
|
}[]) => void;
|
|
21
25
|
replaceLineEntries: (startFen: string, entries: {
|
|
22
26
|
fen: string;
|
|
23
27
|
lastSan: string;
|
|
28
|
+
lastUci?: string;
|
|
24
29
|
}[]) => void;
|
|
25
30
|
goBack: () => PositionHistoryEntry | null;
|
|
26
31
|
goForward: () => PositionHistoryEntry | null;
|
|
@@ -28,6 +28,7 @@ export declare function usePositionReferenceData({ fenProp, onFenChange, initial
|
|
|
28
28
|
canGoForward: boolean;
|
|
29
29
|
forwardSans: string[];
|
|
30
30
|
selectedVariationKey: string | undefined;
|
|
31
|
+
lastMoveUci: string | null;
|
|
31
32
|
setSources: import("react").Dispatch<import("react").SetStateAction<GameSource[]>>;
|
|
32
33
|
setGamesMoveFilterUci: import("react").Dispatch<import("react").SetStateAction<string | undefined>>;
|
|
33
34
|
handleMoveSelect: (move: PositionMoveApiDto) => void;
|
|
@@ -10,6 +10,7 @@ export declare function applyBoardMove(fen: string, sourceSquare: string, target
|
|
|
10
10
|
export type LineSansEntry = {
|
|
11
11
|
fen: string;
|
|
12
12
|
lastSan: string;
|
|
13
|
+
lastUci: string;
|
|
13
14
|
};
|
|
14
15
|
/** Play a SAN sequence from a start FEN; returns null if any move is illegal. */
|
|
15
16
|
export declare function applyLineSans(startFen: string, sans: string[]): {
|
package/dist/index.esm.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Chess } from 'chess.js';
|
|
2
2
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
3
|
-
import { ThemeProvider, HighlightChessboard, usePositionKeyboardNav, ChessboardDnDProvider } from 'react-chess-core';
|
|
3
|
+
import { ThemeProvider, HighlightChessboard, usePositionKeyboardNav, ChessboardDnDProvider, lastMoveUciAtPly } from 'react-chess-core';
|
|
4
4
|
import { useEffect, useState, useCallback, useRef, useMemo } from 'react';
|
|
5
5
|
|
|
6
6
|
/** Standard start position — placeholder until game replay is implemented. */
|
|
@@ -39,6 +39,7 @@ function applyBoardMove(fen, sourceSquare, targetSquare, piece) {
|
|
|
39
39
|
}
|
|
40
40
|
/** Play a SAN sequence from a start FEN; returns null if any move is illegal. */
|
|
41
41
|
function applyLineSans(startFen, sans) {
|
|
42
|
+
var _a;
|
|
42
43
|
const chess = new Chess(startFen);
|
|
43
44
|
const entries = [];
|
|
44
45
|
for (const san of sans) {
|
|
@@ -46,9 +47,10 @@ function applyLineSans(startFen, sans) {
|
|
|
46
47
|
const move = chess.move(san);
|
|
47
48
|
if (!move)
|
|
48
49
|
return null;
|
|
49
|
-
|
|
50
|
+
const lastUci = `${move.from}${move.to}${(_a = move.promotion) !== null && _a !== void 0 ? _a : ""}`;
|
|
51
|
+
entries.push({ fen: chess.fen(), lastSan: move.san, lastUci });
|
|
50
52
|
}
|
|
51
|
-
catch (
|
|
53
|
+
catch (_b) {
|
|
52
54
|
return null;
|
|
53
55
|
}
|
|
54
56
|
}
|
|
@@ -432,30 +434,31 @@ function useExplorerPrefetch({ fen, moves, positionReady, sources, fetchPosition
|
|
|
432
434
|
return;
|
|
433
435
|
}
|
|
434
436
|
const sourcesParam = sources.length < ALL_GAME_SOURCES.length ? sources : undefined;
|
|
435
|
-
|
|
437
|
+
const prefetchMove = (move) => {
|
|
436
438
|
const childFen = fenAfterUci(fen, move.uci);
|
|
437
439
|
if (!childFen) {
|
|
438
|
-
|
|
440
|
+
return Promise.resolve();
|
|
439
441
|
}
|
|
440
442
|
const gamesKey = gamesSessionKey({
|
|
441
443
|
fen: childFen,
|
|
442
444
|
sources: sourcesParam,
|
|
443
445
|
});
|
|
444
|
-
|
|
445
|
-
|
|
446
|
+
const gamesPromise = peekSessionGames(gamesKey)
|
|
447
|
+
? Promise.resolve()
|
|
448
|
+
: fetchPositionGames({ fen: childFen, sources: sourcesParam })
|
|
446
449
|
.then((games) => {
|
|
447
450
|
if (!cancelled) {
|
|
448
451
|
setSessionGames(gamesKey, games);
|
|
449
452
|
}
|
|
450
453
|
})
|
|
451
454
|
.catch(() => undefined);
|
|
452
|
-
}
|
|
453
455
|
if (!fetchPositionVariations) {
|
|
454
|
-
|
|
456
|
+
return gamesPromise;
|
|
455
457
|
}
|
|
456
458
|
const variationsKey = variationsSessionKey(childFen);
|
|
457
|
-
|
|
458
|
-
|
|
459
|
+
const variationsPromise = peekSessionVariations(variationsKey)
|
|
460
|
+
? Promise.resolve()
|
|
461
|
+
: fetchPositionVariations({
|
|
459
462
|
fen: childFen,
|
|
460
463
|
mode: "variations",
|
|
461
464
|
lineCount: EXPLORER_DEFAULT_VARIATION_LINE_COUNT,
|
|
@@ -468,8 +471,17 @@ function useExplorerPrefetch({ fen, moves, positionReady, sources, fetchPosition
|
|
|
468
471
|
}
|
|
469
472
|
})
|
|
470
473
|
.catch(() => undefined);
|
|
474
|
+
return Promise.all([gamesPromise, variationsPromise]).then(() => undefined);
|
|
475
|
+
};
|
|
476
|
+
void (() => __awaiter(this, void 0, void 0, function* () {
|
|
477
|
+
const movesToPrefetch = moves.slice(0, childCount);
|
|
478
|
+
for (let index = 0; index < movesToPrefetch.length; index += 2) {
|
|
479
|
+
if (cancelled) {
|
|
480
|
+
return;
|
|
481
|
+
}
|
|
482
|
+
yield Promise.all(movesToPrefetch.slice(index, index + 2).map(prefetchMove));
|
|
471
483
|
}
|
|
472
|
-
}
|
|
484
|
+
}))();
|
|
473
485
|
};
|
|
474
486
|
if (typeof window.requestIdleCallback === "function") {
|
|
475
487
|
idleHandle = window.requestIdleCallback(prefetchChildren, {
|
|
@@ -513,19 +525,19 @@ function initialHistoryState(initialFen, initialLineSans) {
|
|
|
513
525
|
};
|
|
514
526
|
}
|
|
515
527
|
function usePositionHistory(initialFen, initialLineSans) {
|
|
516
|
-
var _a, _b;
|
|
528
|
+
var _a, _b, _c, _d;
|
|
517
529
|
const [history, setHistory] = useState(() => initialHistoryState(initialFen, initialLineSans).history);
|
|
518
530
|
const [historyIndex, setHistoryIndex] = useState(() => initialHistoryState(initialFen, initialLineSans).historyIndex);
|
|
519
531
|
const canGoBack = historyIndex > 0;
|
|
520
532
|
const canGoForward = historyIndex < history.length - 1;
|
|
521
|
-
const pushEntry = useCallback((fen, lastSan) => {
|
|
533
|
+
const pushEntry = useCallback((fen, lastSan, lastUci) => {
|
|
522
534
|
setHistory((prev) => {
|
|
523
535
|
const trimmed = prev.slice(0, historyIndex + 1);
|
|
524
|
-
const next = [...trimmed, { fen, lastSan }];
|
|
536
|
+
const next = [...trimmed, { fen, lastSan, lastUci }];
|
|
525
537
|
setHistoryIndex(next.length - 1);
|
|
526
538
|
return next;
|
|
527
539
|
});
|
|
528
|
-
return { fen, lastSan };
|
|
540
|
+
return { fen, lastSan, lastUci };
|
|
529
541
|
}, [historyIndex]);
|
|
530
542
|
const goBack = useCallback(() => {
|
|
531
543
|
if (historyIndex <= 0)
|
|
@@ -586,12 +598,14 @@ function usePositionHistory(initialFen, initialLineSans) {
|
|
|
586
598
|
setHistory([{ fen: startFen }, ...entries]);
|
|
587
599
|
setHistoryIndex(entries.length);
|
|
588
600
|
}, []);
|
|
601
|
+
const lastMoveUci = historyIndex > 0 ? (_d = (_c = history[historyIndex]) === null || _c === void 0 ? void 0 : _c.lastUci) !== null && _d !== void 0 ? _d : null : null;
|
|
589
602
|
return {
|
|
590
603
|
canGoBack,
|
|
591
604
|
canGoForward,
|
|
592
605
|
lineSans,
|
|
593
606
|
forwardSans,
|
|
594
607
|
currentFen,
|
|
608
|
+
lastMoveUci,
|
|
595
609
|
pushEntry,
|
|
596
610
|
pushEntries,
|
|
597
611
|
replaceLineEntries,
|
|
@@ -636,7 +650,7 @@ function usePositionReferenceData({ fenProp, onFenChange, initialLineSans, onLin
|
|
|
636
650
|
}
|
|
637
651
|
isAnimatingVariationRef.current = false;
|
|
638
652
|
}, []);
|
|
639
|
-
const { canGoBack, canGoForward, lineSans, forwardSans, currentFen, pushEntry, pushEntries, replaceLineEntries, goBack, goForward, goFirst, goLast, resetHistory, } = usePositionHistory(initialFen, initialLineSans);
|
|
653
|
+
const { canGoBack, canGoForward, lineSans, forwardSans, currentFen, pushEntry, pushEntries, replaceLineEntries, goBack, goForward, goFirst, goLast, resetHistory, lastMoveUci: historyLastMoveUci, } = usePositionHistory(initialFen, initialLineSans);
|
|
640
654
|
/** FEN used for explorer API queries — follows move history, not animation frames. */
|
|
641
655
|
const queryFen = currentFen;
|
|
642
656
|
const initialLineKey = useMemo(() => { var _a; return (_a = initialLineSans === null || initialLineSans === void 0 ? void 0 : initialLineSans.join("|")) !== null && _a !== void 0 ? _a : ""; }, [initialLineSans]);
|
|
@@ -671,6 +685,10 @@ function usePositionReferenceData({ fenProp, onFenChange, initialLineSans, onLin
|
|
|
671
685
|
}), [sources]);
|
|
672
686
|
const lastAppliedLineKeyRef = useRef(initialLineKey);
|
|
673
687
|
useEffect(() => () => cancelVariationAnimation(), [cancelVariationAnimation]);
|
|
688
|
+
// Hold URL line callbacks until history catches up after an external line change.
|
|
689
|
+
useEffect(() => {
|
|
690
|
+
readyForLineSyncRef.current = false;
|
|
691
|
+
}, [initialLineKey]);
|
|
674
692
|
// Apply URL line changes only when the external line key changes — not when the
|
|
675
693
|
// user clicks moves (internal lineSans updates must not re-sync from stale props).
|
|
676
694
|
useEffect(() => {
|
|
@@ -881,7 +899,7 @@ function usePositionReferenceData({ fenProp, onFenChange, initialLineSans, onLin
|
|
|
881
899
|
const nextFen = fenAfterUci(queryFen, move.uci);
|
|
882
900
|
if (!nextFen)
|
|
883
901
|
return;
|
|
884
|
-
pushEntry(nextFen, move.san);
|
|
902
|
+
pushEntry(nextFen, move.san, move.uci);
|
|
885
903
|
setSelectedVariationKey(undefined);
|
|
886
904
|
applyNavigation(nextFen, true);
|
|
887
905
|
}, [queryFen, pushEntry, applyNavigation, cancelVariationAnimation]);
|
|
@@ -895,7 +913,11 @@ function usePositionReferenceData({ fenProp, onFenChange, initialLineSans, onLin
|
|
|
895
913
|
const nextFen = fenAfterUci(lineFen, line.uciPath[i]);
|
|
896
914
|
if (!nextFen)
|
|
897
915
|
return;
|
|
898
|
-
entries.push({
|
|
916
|
+
entries.push({
|
|
917
|
+
fen: nextFen,
|
|
918
|
+
lastSan: line.moves[i].san,
|
|
919
|
+
lastUci: line.uciPath[i],
|
|
920
|
+
});
|
|
899
921
|
lineFen = nextFen;
|
|
900
922
|
}
|
|
901
923
|
if (entries.length === 0)
|
|
@@ -930,7 +952,7 @@ function usePositionReferenceData({ fenProp, onFenChange, initialLineSans, onLin
|
|
|
930
952
|
const result = applyBoardMove(queryFen, sourceSquare, targetSquare, piece);
|
|
931
953
|
if (!result)
|
|
932
954
|
return false;
|
|
933
|
-
pushEntry(result.fen, result.san);
|
|
955
|
+
pushEntry(result.fen, result.san, result.uci);
|
|
934
956
|
setSelectedVariationKey(undefined);
|
|
935
957
|
applyNavigation(result.fen, true);
|
|
936
958
|
return true;
|
|
@@ -1007,6 +1029,7 @@ function usePositionReferenceData({ fenProp, onFenChange, initialLineSans, onLin
|
|
|
1007
1029
|
canGoForward,
|
|
1008
1030
|
forwardSans,
|
|
1009
1031
|
selectedVariationKey,
|
|
1032
|
+
lastMoveUci: historyLastMoveUci,
|
|
1010
1033
|
setSources,
|
|
1011
1034
|
setGamesMoveFilterUci,
|
|
1012
1035
|
handleMoveSelect,
|
|
@@ -1105,7 +1128,7 @@ const PositionReferenceExplorerCore = ({ fen: fenProp, onFenChange, initialLineS
|
|
|
1105
1128
|
fetchPositionGames,
|
|
1106
1129
|
fetchPositionVariations,
|
|
1107
1130
|
});
|
|
1108
|
-
const { fen, boardFen, games, sources, lineSans, loading, showPositionLoading, gamesLoading, positionReady, displayMoves, error, lineLabel, canGoBack, canGoForward, forwardSans, selectedVariationKey, setSources, handleMoveSelect, handleLineSelect, handlePieceDrop, handleBack, handleForward, handleFirst, handleLast, } = referenceData;
|
|
1131
|
+
const { fen, boardFen, games, sources, lineSans, loading, showPositionLoading, gamesLoading, positionReady, displayMoves, error, lineLabel, canGoBack, canGoForward, forwardSans, selectedVariationKey, lastMoveUci, setSources, handleMoveSelect, handleLineSelect, handlePieceDrop, handleBack, handleForward, handleFirst, handleLast, } = referenceData;
|
|
1109
1132
|
usePositionKeyboardNav({
|
|
1110
1133
|
enabled: keyboardNav,
|
|
1111
1134
|
canPrev: canGoBack,
|
|
@@ -1169,7 +1192,7 @@ const PositionReferenceExplorerCore = ({ fen: fenProp, onFenChange, initialLineS
|
|
|
1169
1192
|
overflow: fillHeight ? "hidden" : "visible",
|
|
1170
1193
|
boxSizing: "border-box",
|
|
1171
1194
|
};
|
|
1172
|
-
const board = (jsxs(Fragment, { children: [jsx(ChessboardDnDProvider, { children: jsx(HighlightChessboard, { boardWidth: boardWidth, position: boardFen, boardOrientation: boardOrientation, checkSquare: "", hintSquare: null, incorrectMoveSquare: null, onPieceDrop: handlePieceDrop, promotionDialogVariant: "modal" }, boardOrientation) }), renderBoardNav(boardNavProps)] }));
|
|
1195
|
+
const board = (jsxs(Fragment, { children: [jsx(ChessboardDnDProvider, { children: jsx(HighlightChessboard, { boardWidth: boardWidth, position: boardFen, boardOrientation: boardOrientation, checkSquare: "", hintSquare: null, incorrectMoveSquare: null, lastMoveUci: lastMoveUci, onPieceDrop: handlePieceDrop, promotionDialogVariant: "modal" }, boardOrientation) }), renderBoardNav(boardNavProps)] }));
|
|
1173
1196
|
const referencePanel = (jsx(DefaultReferencePanel, { theme: theme, fillHeight: fillHeight, status: renderStatus({
|
|
1174
1197
|
error,
|
|
1175
1198
|
loading: showPositionLoading,
|
|
@@ -1291,6 +1314,7 @@ function useGameReplayTraining({ gameId, startFen, fetchGame, }) {
|
|
|
1291
1314
|
const complete = game ? plyIndex >= game.movesUci.length : false;
|
|
1292
1315
|
const expectedUci = game === null || game === void 0 ? void 0 : game.movesUci[plyIndex];
|
|
1293
1316
|
const expectedSan = game === null || game === void 0 ? void 0 : game.movesSan[plyIndex];
|
|
1317
|
+
const lastMoveUci = useMemo(() => (game ? lastMoveUciAtPly(game.movesUci, plyIndex) : null), [game, plyIndex]);
|
|
1294
1318
|
const handlePieceDrop = useCallback((sourceSquare, targetSquare, piece) => {
|
|
1295
1319
|
if (!game || complete || !expectedUci)
|
|
1296
1320
|
return false;
|
|
@@ -1324,6 +1348,7 @@ function useGameReplayTraining({ gameId, startFen, fetchGame, }) {
|
|
|
1324
1348
|
error,
|
|
1325
1349
|
feedback,
|
|
1326
1350
|
lastExpectedSan,
|
|
1351
|
+
lastMoveUci,
|
|
1327
1352
|
expectedSan,
|
|
1328
1353
|
handlePieceDrop,
|
|
1329
1354
|
revealMove,
|
|
@@ -1344,7 +1369,7 @@ const defaultButtonStyle = {
|
|
|
1344
1369
|
cursor: "pointer",
|
|
1345
1370
|
};
|
|
1346
1371
|
const GameReplayTrainer = ({ gameId, startFen, fetchGame, onExit, theme = "dark", boardWidth = DEFAULT_REFERENCE_LAYOUT.boardWidth, renderStatus, }) => {
|
|
1347
|
-
const { game, fen, plyIndex, totalPlies, complete, loading, error, feedback, lastExpectedSan, handlePieceDrop, revealMove, } = useGameReplayTraining({ gameId, startFen, fetchGame });
|
|
1372
|
+
const { game, fen, plyIndex, totalPlies, complete, loading, error, feedback, lastExpectedSan, lastMoveUci, handlePieceDrop, revealMove, } = useGameReplayTraining({ gameId, startFen, fetchGame });
|
|
1348
1373
|
const status = renderStatus === null || renderStatus === void 0 ? void 0 : renderStatus({
|
|
1349
1374
|
loading,
|
|
1350
1375
|
error,
|
|
@@ -1364,7 +1389,7 @@ const GameReplayTrainer = ({ gameId, startFen, fetchGame, onExit, theme = "dark"
|
|
|
1364
1389
|
!error &&
|
|
1365
1390
|
!complete &&
|
|
1366
1391
|
feedback === "incorrect" &&
|
|
1367
|
-
lastExpectedSan && (jsxs("span", { style: { color: "#ef6c00" }, children: ["Expected ", lastExpectedSan] })), !loading && !error && !complete && feedback === null && (jsxs("span", { children: ["Guess move ", plyIndex + 1, " of ", totalPlies] }))] })), jsx(ChessboardDnDProvider, { children: jsx(HighlightChessboard, { boardWidth: boardWidth, position: fen, checkSquare: "", hintSquare: null, incorrectMoveSquare: null, onPieceDrop: handlePieceDrop, promotionDialogVariant: "modal" }) }), !complete && !loading && !error && (jsx("button", { type: "button", style: defaultButtonStyle, onClick: revealMove, children: "Show move" }))] }) }));
|
|
1392
|
+
lastExpectedSan && (jsxs("span", { style: { color: "#ef6c00" }, children: ["Expected ", lastExpectedSan] })), !loading && !error && !complete && feedback === null && (jsxs("span", { children: ["Guess move ", plyIndex + 1, " of ", totalPlies] }))] })), jsx(ChessboardDnDProvider, { children: jsx(HighlightChessboard, { boardWidth: boardWidth, position: fen, checkSquare: "", hintSquare: null, incorrectMoveSquare: null, lastMoveUci: lastMoveUci, onPieceDrop: handlePieceDrop, promotionDialogVariant: "modal" }) }), !complete && !loading && !error && (jsx("button", { type: "button", style: defaultButtonStyle, onClick: revealMove, children: "Show move" }))] }) }));
|
|
1368
1393
|
};
|
|
1369
1394
|
|
|
1370
1395
|
const mockPosition = {
|
package/dist/index.js
CHANGED
|
@@ -41,6 +41,7 @@ function applyBoardMove(fen, sourceSquare, targetSquare, piece) {
|
|
|
41
41
|
}
|
|
42
42
|
/** Play a SAN sequence from a start FEN; returns null if any move is illegal. */
|
|
43
43
|
function applyLineSans(startFen, sans) {
|
|
44
|
+
var _a;
|
|
44
45
|
const chess = new chess_js.Chess(startFen);
|
|
45
46
|
const entries = [];
|
|
46
47
|
for (const san of sans) {
|
|
@@ -48,9 +49,10 @@ function applyLineSans(startFen, sans) {
|
|
|
48
49
|
const move = chess.move(san);
|
|
49
50
|
if (!move)
|
|
50
51
|
return null;
|
|
51
|
-
|
|
52
|
+
const lastUci = `${move.from}${move.to}${(_a = move.promotion) !== null && _a !== void 0 ? _a : ""}`;
|
|
53
|
+
entries.push({ fen: chess.fen(), lastSan: move.san, lastUci });
|
|
52
54
|
}
|
|
53
|
-
catch (
|
|
55
|
+
catch (_b) {
|
|
54
56
|
return null;
|
|
55
57
|
}
|
|
56
58
|
}
|
|
@@ -434,30 +436,31 @@ function useExplorerPrefetch({ fen, moves, positionReady, sources, fetchPosition
|
|
|
434
436
|
return;
|
|
435
437
|
}
|
|
436
438
|
const sourcesParam = sources.length < ALL_GAME_SOURCES.length ? sources : undefined;
|
|
437
|
-
|
|
439
|
+
const prefetchMove = (move) => {
|
|
438
440
|
const childFen = fenAfterUci(fen, move.uci);
|
|
439
441
|
if (!childFen) {
|
|
440
|
-
|
|
442
|
+
return Promise.resolve();
|
|
441
443
|
}
|
|
442
444
|
const gamesKey = gamesSessionKey({
|
|
443
445
|
fen: childFen,
|
|
444
446
|
sources: sourcesParam,
|
|
445
447
|
});
|
|
446
|
-
|
|
447
|
-
|
|
448
|
+
const gamesPromise = peekSessionGames(gamesKey)
|
|
449
|
+
? Promise.resolve()
|
|
450
|
+
: fetchPositionGames({ fen: childFen, sources: sourcesParam })
|
|
448
451
|
.then((games) => {
|
|
449
452
|
if (!cancelled) {
|
|
450
453
|
setSessionGames(gamesKey, games);
|
|
451
454
|
}
|
|
452
455
|
})
|
|
453
456
|
.catch(() => undefined);
|
|
454
|
-
}
|
|
455
457
|
if (!fetchPositionVariations) {
|
|
456
|
-
|
|
458
|
+
return gamesPromise;
|
|
457
459
|
}
|
|
458
460
|
const variationsKey = variationsSessionKey(childFen);
|
|
459
|
-
|
|
460
|
-
|
|
461
|
+
const variationsPromise = peekSessionVariations(variationsKey)
|
|
462
|
+
? Promise.resolve()
|
|
463
|
+
: fetchPositionVariations({
|
|
461
464
|
fen: childFen,
|
|
462
465
|
mode: "variations",
|
|
463
466
|
lineCount: EXPLORER_DEFAULT_VARIATION_LINE_COUNT,
|
|
@@ -470,8 +473,17 @@ function useExplorerPrefetch({ fen, moves, positionReady, sources, fetchPosition
|
|
|
470
473
|
}
|
|
471
474
|
})
|
|
472
475
|
.catch(() => undefined);
|
|
476
|
+
return Promise.all([gamesPromise, variationsPromise]).then(() => undefined);
|
|
477
|
+
};
|
|
478
|
+
void (() => __awaiter(this, void 0, void 0, function* () {
|
|
479
|
+
const movesToPrefetch = moves.slice(0, childCount);
|
|
480
|
+
for (let index = 0; index < movesToPrefetch.length; index += 2) {
|
|
481
|
+
if (cancelled) {
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
yield Promise.all(movesToPrefetch.slice(index, index + 2).map(prefetchMove));
|
|
473
485
|
}
|
|
474
|
-
}
|
|
486
|
+
}))();
|
|
475
487
|
};
|
|
476
488
|
if (typeof window.requestIdleCallback === "function") {
|
|
477
489
|
idleHandle = window.requestIdleCallback(prefetchChildren, {
|
|
@@ -515,19 +527,19 @@ function initialHistoryState(initialFen, initialLineSans) {
|
|
|
515
527
|
};
|
|
516
528
|
}
|
|
517
529
|
function usePositionHistory(initialFen, initialLineSans) {
|
|
518
|
-
var _a, _b;
|
|
530
|
+
var _a, _b, _c, _d;
|
|
519
531
|
const [history, setHistory] = react.useState(() => initialHistoryState(initialFen, initialLineSans).history);
|
|
520
532
|
const [historyIndex, setHistoryIndex] = react.useState(() => initialHistoryState(initialFen, initialLineSans).historyIndex);
|
|
521
533
|
const canGoBack = historyIndex > 0;
|
|
522
534
|
const canGoForward = historyIndex < history.length - 1;
|
|
523
|
-
const pushEntry = react.useCallback((fen, lastSan) => {
|
|
535
|
+
const pushEntry = react.useCallback((fen, lastSan, lastUci) => {
|
|
524
536
|
setHistory((prev) => {
|
|
525
537
|
const trimmed = prev.slice(0, historyIndex + 1);
|
|
526
|
-
const next = [...trimmed, { fen, lastSan }];
|
|
538
|
+
const next = [...trimmed, { fen, lastSan, lastUci }];
|
|
527
539
|
setHistoryIndex(next.length - 1);
|
|
528
540
|
return next;
|
|
529
541
|
});
|
|
530
|
-
return { fen, lastSan };
|
|
542
|
+
return { fen, lastSan, lastUci };
|
|
531
543
|
}, [historyIndex]);
|
|
532
544
|
const goBack = react.useCallback(() => {
|
|
533
545
|
if (historyIndex <= 0)
|
|
@@ -588,12 +600,14 @@ function usePositionHistory(initialFen, initialLineSans) {
|
|
|
588
600
|
setHistory([{ fen: startFen }, ...entries]);
|
|
589
601
|
setHistoryIndex(entries.length);
|
|
590
602
|
}, []);
|
|
603
|
+
const lastMoveUci = historyIndex > 0 ? (_d = (_c = history[historyIndex]) === null || _c === void 0 ? void 0 : _c.lastUci) !== null && _d !== void 0 ? _d : null : null;
|
|
591
604
|
return {
|
|
592
605
|
canGoBack,
|
|
593
606
|
canGoForward,
|
|
594
607
|
lineSans,
|
|
595
608
|
forwardSans,
|
|
596
609
|
currentFen,
|
|
610
|
+
lastMoveUci,
|
|
597
611
|
pushEntry,
|
|
598
612
|
pushEntries,
|
|
599
613
|
replaceLineEntries,
|
|
@@ -638,7 +652,7 @@ function usePositionReferenceData({ fenProp, onFenChange, initialLineSans, onLin
|
|
|
638
652
|
}
|
|
639
653
|
isAnimatingVariationRef.current = false;
|
|
640
654
|
}, []);
|
|
641
|
-
const { canGoBack, canGoForward, lineSans, forwardSans, currentFen, pushEntry, pushEntries, replaceLineEntries, goBack, goForward, goFirst, goLast, resetHistory, } = usePositionHistory(initialFen, initialLineSans);
|
|
655
|
+
const { canGoBack, canGoForward, lineSans, forwardSans, currentFen, pushEntry, pushEntries, replaceLineEntries, goBack, goForward, goFirst, goLast, resetHistory, lastMoveUci: historyLastMoveUci, } = usePositionHistory(initialFen, initialLineSans);
|
|
642
656
|
/** FEN used for explorer API queries — follows move history, not animation frames. */
|
|
643
657
|
const queryFen = currentFen;
|
|
644
658
|
const initialLineKey = react.useMemo(() => { var _a; return (_a = initialLineSans === null || initialLineSans === void 0 ? void 0 : initialLineSans.join("|")) !== null && _a !== void 0 ? _a : ""; }, [initialLineSans]);
|
|
@@ -673,6 +687,10 @@ function usePositionReferenceData({ fenProp, onFenChange, initialLineSans, onLin
|
|
|
673
687
|
}), [sources]);
|
|
674
688
|
const lastAppliedLineKeyRef = react.useRef(initialLineKey);
|
|
675
689
|
react.useEffect(() => () => cancelVariationAnimation(), [cancelVariationAnimation]);
|
|
690
|
+
// Hold URL line callbacks until history catches up after an external line change.
|
|
691
|
+
react.useEffect(() => {
|
|
692
|
+
readyForLineSyncRef.current = false;
|
|
693
|
+
}, [initialLineKey]);
|
|
676
694
|
// Apply URL line changes only when the external line key changes — not when the
|
|
677
695
|
// user clicks moves (internal lineSans updates must not re-sync from stale props).
|
|
678
696
|
react.useEffect(() => {
|
|
@@ -883,7 +901,7 @@ function usePositionReferenceData({ fenProp, onFenChange, initialLineSans, onLin
|
|
|
883
901
|
const nextFen = fenAfterUci(queryFen, move.uci);
|
|
884
902
|
if (!nextFen)
|
|
885
903
|
return;
|
|
886
|
-
pushEntry(nextFen, move.san);
|
|
904
|
+
pushEntry(nextFen, move.san, move.uci);
|
|
887
905
|
setSelectedVariationKey(undefined);
|
|
888
906
|
applyNavigation(nextFen, true);
|
|
889
907
|
}, [queryFen, pushEntry, applyNavigation, cancelVariationAnimation]);
|
|
@@ -897,7 +915,11 @@ function usePositionReferenceData({ fenProp, onFenChange, initialLineSans, onLin
|
|
|
897
915
|
const nextFen = fenAfterUci(lineFen, line.uciPath[i]);
|
|
898
916
|
if (!nextFen)
|
|
899
917
|
return;
|
|
900
|
-
entries.push({
|
|
918
|
+
entries.push({
|
|
919
|
+
fen: nextFen,
|
|
920
|
+
lastSan: line.moves[i].san,
|
|
921
|
+
lastUci: line.uciPath[i],
|
|
922
|
+
});
|
|
901
923
|
lineFen = nextFen;
|
|
902
924
|
}
|
|
903
925
|
if (entries.length === 0)
|
|
@@ -932,7 +954,7 @@ function usePositionReferenceData({ fenProp, onFenChange, initialLineSans, onLin
|
|
|
932
954
|
const result = applyBoardMove(queryFen, sourceSquare, targetSquare, piece);
|
|
933
955
|
if (!result)
|
|
934
956
|
return false;
|
|
935
|
-
pushEntry(result.fen, result.san);
|
|
957
|
+
pushEntry(result.fen, result.san, result.uci);
|
|
936
958
|
setSelectedVariationKey(undefined);
|
|
937
959
|
applyNavigation(result.fen, true);
|
|
938
960
|
return true;
|
|
@@ -1009,6 +1031,7 @@ function usePositionReferenceData({ fenProp, onFenChange, initialLineSans, onLin
|
|
|
1009
1031
|
canGoForward,
|
|
1010
1032
|
forwardSans,
|
|
1011
1033
|
selectedVariationKey,
|
|
1034
|
+
lastMoveUci: historyLastMoveUci,
|
|
1012
1035
|
setSources,
|
|
1013
1036
|
setGamesMoveFilterUci,
|
|
1014
1037
|
handleMoveSelect,
|
|
@@ -1107,7 +1130,7 @@ const PositionReferenceExplorerCore = ({ fen: fenProp, onFenChange, initialLineS
|
|
|
1107
1130
|
fetchPositionGames,
|
|
1108
1131
|
fetchPositionVariations,
|
|
1109
1132
|
});
|
|
1110
|
-
const { fen, boardFen, games, sources, lineSans, loading, showPositionLoading, gamesLoading, positionReady, displayMoves, error, lineLabel, canGoBack, canGoForward, forwardSans, selectedVariationKey, setSources, handleMoveSelect, handleLineSelect, handlePieceDrop, handleBack, handleForward, handleFirst, handleLast, } = referenceData;
|
|
1133
|
+
const { fen, boardFen, games, sources, lineSans, loading, showPositionLoading, gamesLoading, positionReady, displayMoves, error, lineLabel, canGoBack, canGoForward, forwardSans, selectedVariationKey, lastMoveUci, setSources, handleMoveSelect, handleLineSelect, handlePieceDrop, handleBack, handleForward, handleFirst, handleLast, } = referenceData;
|
|
1111
1134
|
reactChessCore.usePositionKeyboardNav({
|
|
1112
1135
|
enabled: keyboardNav,
|
|
1113
1136
|
canPrev: canGoBack,
|
|
@@ -1171,7 +1194,7 @@ const PositionReferenceExplorerCore = ({ fen: fenProp, onFenChange, initialLineS
|
|
|
1171
1194
|
overflow: fillHeight ? "hidden" : "visible",
|
|
1172
1195
|
boxSizing: "border-box",
|
|
1173
1196
|
};
|
|
1174
|
-
const board = (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(reactChessCore.ChessboardDnDProvider, { children: jsxRuntime.jsx(reactChessCore.HighlightChessboard, { boardWidth: boardWidth, position: boardFen, boardOrientation: boardOrientation, checkSquare: "", hintSquare: null, incorrectMoveSquare: null, onPieceDrop: handlePieceDrop, promotionDialogVariant: "modal" }, boardOrientation) }), renderBoardNav(boardNavProps)] }));
|
|
1197
|
+
const board = (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(reactChessCore.ChessboardDnDProvider, { children: jsxRuntime.jsx(reactChessCore.HighlightChessboard, { boardWidth: boardWidth, position: boardFen, boardOrientation: boardOrientation, checkSquare: "", hintSquare: null, incorrectMoveSquare: null, lastMoveUci: lastMoveUci, onPieceDrop: handlePieceDrop, promotionDialogVariant: "modal" }, boardOrientation) }), renderBoardNav(boardNavProps)] }));
|
|
1175
1198
|
const referencePanel = (jsxRuntime.jsx(DefaultReferencePanel, { theme: theme, fillHeight: fillHeight, status: renderStatus({
|
|
1176
1199
|
error,
|
|
1177
1200
|
loading: showPositionLoading,
|
|
@@ -1293,6 +1316,7 @@ function useGameReplayTraining({ gameId, startFen, fetchGame, }) {
|
|
|
1293
1316
|
const complete = game ? plyIndex >= game.movesUci.length : false;
|
|
1294
1317
|
const expectedUci = game === null || game === void 0 ? void 0 : game.movesUci[plyIndex];
|
|
1295
1318
|
const expectedSan = game === null || game === void 0 ? void 0 : game.movesSan[plyIndex];
|
|
1319
|
+
const lastMoveUci = react.useMemo(() => (game ? reactChessCore.lastMoveUciAtPly(game.movesUci, plyIndex) : null), [game, plyIndex]);
|
|
1296
1320
|
const handlePieceDrop = react.useCallback((sourceSquare, targetSquare, piece) => {
|
|
1297
1321
|
if (!game || complete || !expectedUci)
|
|
1298
1322
|
return false;
|
|
@@ -1326,6 +1350,7 @@ function useGameReplayTraining({ gameId, startFen, fetchGame, }) {
|
|
|
1326
1350
|
error,
|
|
1327
1351
|
feedback,
|
|
1328
1352
|
lastExpectedSan,
|
|
1353
|
+
lastMoveUci,
|
|
1329
1354
|
expectedSan,
|
|
1330
1355
|
handlePieceDrop,
|
|
1331
1356
|
revealMove,
|
|
@@ -1346,7 +1371,7 @@ const defaultButtonStyle = {
|
|
|
1346
1371
|
cursor: "pointer",
|
|
1347
1372
|
};
|
|
1348
1373
|
const GameReplayTrainer = ({ gameId, startFen, fetchGame, onExit, theme = "dark", boardWidth = DEFAULT_REFERENCE_LAYOUT.boardWidth, renderStatus, }) => {
|
|
1349
|
-
const { game, fen, plyIndex, totalPlies, complete, loading, error, feedback, lastExpectedSan, handlePieceDrop, revealMove, } = useGameReplayTraining({ gameId, startFen, fetchGame });
|
|
1374
|
+
const { game, fen, plyIndex, totalPlies, complete, loading, error, feedback, lastExpectedSan, lastMoveUci, handlePieceDrop, revealMove, } = useGameReplayTraining({ gameId, startFen, fetchGame });
|
|
1350
1375
|
const status = renderStatus === null || renderStatus === void 0 ? void 0 : renderStatus({
|
|
1351
1376
|
loading,
|
|
1352
1377
|
error,
|
|
@@ -1366,7 +1391,7 @@ const GameReplayTrainer = ({ gameId, startFen, fetchGame, onExit, theme = "dark"
|
|
|
1366
1391
|
!error &&
|
|
1367
1392
|
!complete &&
|
|
1368
1393
|
feedback === "incorrect" &&
|
|
1369
|
-
lastExpectedSan && (jsxRuntime.jsxs("span", { style: { color: "#ef6c00" }, children: ["Expected ", lastExpectedSan] })), !loading && !error && !complete && feedback === null && (jsxRuntime.jsxs("span", { children: ["Guess move ", plyIndex + 1, " of ", totalPlies] }))] })), jsxRuntime.jsx(reactChessCore.ChessboardDnDProvider, { children: jsxRuntime.jsx(reactChessCore.HighlightChessboard, { boardWidth: boardWidth, position: fen, checkSquare: "", hintSquare: null, incorrectMoveSquare: null, onPieceDrop: handlePieceDrop, promotionDialogVariant: "modal" }) }), !complete && !loading && !error && (jsxRuntime.jsx("button", { type: "button", style: defaultButtonStyle, onClick: revealMove, children: "Show move" }))] }) }));
|
|
1394
|
+
lastExpectedSan && (jsxRuntime.jsxs("span", { style: { color: "#ef6c00" }, children: ["Expected ", lastExpectedSan] })), !loading && !error && !complete && feedback === null && (jsxRuntime.jsxs("span", { children: ["Guess move ", plyIndex + 1, " of ", totalPlies] }))] })), jsxRuntime.jsx(reactChessCore.ChessboardDnDProvider, { children: jsxRuntime.jsx(reactChessCore.HighlightChessboard, { boardWidth: boardWidth, position: fen, checkSquare: "", hintSquare: null, incorrectMoveSquare: null, lastMoveUci: lastMoveUci, onPieceDrop: handlePieceDrop, promotionDialogVariant: "modal" }) }), !complete && !loading && !error && (jsxRuntime.jsx("button", { type: "button", style: defaultButtonStyle, onClick: revealMove, children: "Show move" }))] }) }));
|
|
1370
1395
|
};
|
|
1371
1396
|
|
|
1372
1397
|
const mockPosition = {
|
package/package.json
CHANGED
|
@@ -1,59 +1,59 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "react-chess-explorer",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "React components for browsing and replaying chess games (depends on react-chess-core only)",
|
|
5
|
-
"license": "MIT",
|
|
6
|
-
"author": "Robert Blackwell",
|
|
7
|
-
"main": "dist/index.js",
|
|
8
|
-
"module": "dist/index.esm.js",
|
|
9
|
-
"types": "dist/index.d.ts",
|
|
10
|
-
"repository": {
|
|
11
|
-
"type": "git",
|
|
12
|
-
"url": "git+https://github.com/reblackwell3/react-chess-explorer.git"
|
|
13
|
-
},
|
|
14
|
-
"files": [
|
|
15
|
-
"dist"
|
|
16
|
-
],
|
|
17
|
-
"scripts": {
|
|
18
|
-
"build": "rollup -c",
|
|
19
|
-
"prepublishOnly": "npm run build",
|
|
20
|
-
"storybook": "storybook dev -p 6008",
|
|
21
|
-
"build-storybook": "storybook build"
|
|
22
|
-
},
|
|
23
|
-
"dependencies": {
|
|
24
|
-
"rollup": "^4.22.2",
|
|
25
|
-
"rollup-plugin-peer-deps-external": "^2.2.4",
|
|
26
|
-
"typescript": "^5.6.2"
|
|
27
|
-
},
|
|
28
|
-
"peerDependencies": {
|
|
29
|
-
"chess.js": "^1.0.0-beta.8",
|
|
30
|
-
"react": "^18.3.1",
|
|
31
|
-
"react-chess-core": "^0.1.1",
|
|
32
|
-
"react-chessboard": "^4.7.1"
|
|
33
|
-
},
|
|
34
|
-
"devDependencies": {
|
|
35
|
-
"@chromatic-com/storybook": "^1.9.0",
|
|
36
|
-
"@rollup/plugin-commonjs": "^26.0.1",
|
|
37
|
-
"@rollup/plugin-node-resolve": "^15.2.3",
|
|
38
|
-
"@rollup/plugin-typescript": "^12.3.0",
|
|
39
|
-
"@storybook/addon-essentials": "^8.2.9",
|
|
40
|
-
"@storybook/addon-interactions": "^8.2.9",
|
|
41
|
-
"@storybook/addon-links": "^8.2.9",
|
|
42
|
-
"@storybook/addon-onboarding": "^8.2.9",
|
|
43
|
-
"@storybook/blocks": "^8.2.9",
|
|
44
|
-
"@storybook/preset-typescript": "^3.0.0",
|
|
45
|
-
"@storybook/react": "^8.2.9",
|
|
46
|
-
"@storybook/react-vite": "^8.2.9",
|
|
47
|
-
"@storybook/test": "^8.2.9",
|
|
48
|
-
"@types/react": "^18.3.12",
|
|
49
|
-
"@types/react-dom": "^18.3.1",
|
|
50
|
-
"@vitejs/plugin-react": "^4.3.1",
|
|
51
|
-
"chess.js": "^1.0.0-beta.8",
|
|
52
|
-
"react": "^18.3.1",
|
|
53
|
-
"react-chess-core": "^0.1.1",
|
|
54
|
-
"react-chessboard": "^4.7.1",
|
|
55
|
-
"react-dom": "^18.3.1",
|
|
56
|
-
"storybook": "^8.2.9",
|
|
57
|
-
"tslib": "^2.8.1"
|
|
58
|
-
}
|
|
59
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "react-chess-explorer",
|
|
3
|
+
"version": "0.0.5",
|
|
4
|
+
"description": "React components for browsing and replaying chess games (depends on react-chess-core only)",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Robert Blackwell",
|
|
7
|
+
"main": "dist/index.js",
|
|
8
|
+
"module": "dist/index.esm.js",
|
|
9
|
+
"types": "dist/index.d.ts",
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "git+https://github.com/reblackwell3/react-chess-explorer.git"
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "rollup -c",
|
|
19
|
+
"prepublishOnly": "npm run build",
|
|
20
|
+
"storybook": "storybook dev -p 6008",
|
|
21
|
+
"build-storybook": "storybook build"
|
|
22
|
+
},
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"rollup": "^4.22.2",
|
|
25
|
+
"rollup-plugin-peer-deps-external": "^2.2.4",
|
|
26
|
+
"typescript": "^5.6.2"
|
|
27
|
+
},
|
|
28
|
+
"peerDependencies": {
|
|
29
|
+
"chess.js": "^1.0.0-beta.8",
|
|
30
|
+
"react": "^18.3.1",
|
|
31
|
+
"react-chess-core": "^0.1.1",
|
|
32
|
+
"react-chessboard": "^4.7.1"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@chromatic-com/storybook": "^1.9.0",
|
|
36
|
+
"@rollup/plugin-commonjs": "^26.0.1",
|
|
37
|
+
"@rollup/plugin-node-resolve": "^15.2.3",
|
|
38
|
+
"@rollup/plugin-typescript": "^12.3.0",
|
|
39
|
+
"@storybook/addon-essentials": "^8.2.9",
|
|
40
|
+
"@storybook/addon-interactions": "^8.2.9",
|
|
41
|
+
"@storybook/addon-links": "^8.2.9",
|
|
42
|
+
"@storybook/addon-onboarding": "^8.2.9",
|
|
43
|
+
"@storybook/blocks": "^8.2.9",
|
|
44
|
+
"@storybook/preset-typescript": "^3.0.0",
|
|
45
|
+
"@storybook/react": "^8.2.9",
|
|
46
|
+
"@storybook/react-vite": "^8.2.9",
|
|
47
|
+
"@storybook/test": "^8.2.9",
|
|
48
|
+
"@types/react": "^18.3.12",
|
|
49
|
+
"@types/react-dom": "^18.3.1",
|
|
50
|
+
"@vitejs/plugin-react": "^4.3.1",
|
|
51
|
+
"chess.js": "^1.0.0-beta.8",
|
|
52
|
+
"react": "^18.3.1",
|
|
53
|
+
"react-chess-core": "^0.1.1",
|
|
54
|
+
"react-chessboard": "^4.7.1",
|
|
55
|
+
"react-dom": "^18.3.1",
|
|
56
|
+
"storybook": "^8.2.9",
|
|
57
|
+
"tslib": "^2.8.1"
|
|
58
|
+
}
|
|
59
|
+
}
|