react-chess-puzzle-kit 1.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +331 -331
- package/dist/index.esm.js +16 -4
- package/dist/index.js +16 -4
- package/package.json +87 -87
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2022-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) 2022-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,331 +1,331 @@
|
|
|
1
|
-
# react-chess-puzzle-kit
|
|
2
|
-
|
|
3
|
-
```bash
|
|
4
|
-
npm install
|
|
5
|
-
npm run build
|
|
6
|
-
```
|
|
7
|
-
|
|
8
|
-
Build output: `dist/` (`index.js`, `index.esm.js`, `index.d.ts`). Re-run after source changes when consuming this package via `file:../react-chess-puzzle-kit`.
|
|
9
|
-
|
|
10
|
-
React components for **interactive chess puzzles** and **post-puzzle analysis**, built on [react-chessboard](https://github.com/Clariity/react-chessboard) and [chess.js](https://github.com/jhlywa/chess.js). Used in production at [endchess.com](https://endchess.com).
|
|
11
|
-
|
|
12
|
-
The library owns puzzle logic, move history, themes, and optional Stockfish analysis. **Defaults are included** for a full demo (controls + analysis UI); production apps usually replace those with custom render props.
|
|
13
|
-
|
|
14
|
-
---
|
|
15
|
-
|
|
16
|
-
## Install
|
|
17
|
-
|
|
18
|
-
```bash
|
|
19
|
-
npm install react-chess-puzzle-kit
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
**Peer dependencies:** `react`, `react-chessboard`, `chess.js`, **`react-chess-core`** (required — see `package.json`).
|
|
23
|
-
|
|
24
|
-
Install both packages in your app:
|
|
25
|
-
|
|
26
|
-
```bash
|
|
27
|
-
npm install react-chess-puzzle-kit react-chess-core
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
Local development: `file:../react-chess-core` and `file:../react-chess-puzzle-kit` — build core first (`npm run build` in that repo), then puzzle-kit, then `npm install` in the app.
|
|
31
|
-
|
|
32
|
-
**Board theme, `HighlightChessboard`, Stockfish hooks, and eval formatters** are exported from **`react-chess-core`**, not re-exported from puzzle-kit. Puzzle-kit covers puzzle play, analysis orchestration, and optional default analysis UI.
|
|
33
|
-
|
|
34
|
-
For engine analysis in the browser, also install Stockfish and copy WASM into your app’s static folder (see [Stockfish](#stockfish-browser-engine) below).
|
|
35
|
-
|
|
36
|
-
---
|
|
37
|
-
|
|
38
|
-
## See it in action (Storybook)
|
|
39
|
-
|
|
40
|
-
Storybook is the living docs and playground for every export.
|
|
41
|
-
|
|
42
|
-
```bash
|
|
43
|
-
git clone https://github.com/reblackwell3/react-chess-puzzle-kit.git
|
|
44
|
-
cd react-chess-puzzle-kit
|
|
45
|
-
npm install
|
|
46
|
-
npm run storybook # http://localhost:6006
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
| Story | What it demonstrates |
|
|
50
|
-
|-------|----------------------|
|
|
51
|
-
| **PuzzleBoardWithControls** | Full puzzle flow with default controls (via decorator) |
|
|
52
|
-
| **PuzzleBoardWithControls → All library defaults** | Default controls + default analysis modal, sidebar, engine panel |
|
|
53
|
-
| **PuzzleBoard** | Puzzle board only (drag-and-drop, feedback highlights) |
|
|
54
|
-
| **Analysis / AnalysisBoard (defaults)** | Default modal, sidebar, grid, and engine panel |
|
|
55
|
-
| **HighlightChessboard** | Themed board with check / hint / incorrect square styles |
|
|
56
|
-
|
|
57
|
-
Optional: `npm run copy:stockfish` then open **Analysis → WithStockfishEngine** to exercise the worker.
|
|
58
|
-
|
|
59
|
-
Build a static catalog: `npm run build-storybook` → `npm run serve-storybook`.
|
|
60
|
-
|
|
61
|
-
---
|
|
62
|
-
|
|
63
|
-
## Quick start
|
|
64
|
-
|
|
65
|
-
`PuzzleBoardWithControls` is the main integration point: puzzle play, then analysis when the puzzle is finished or failed.
|
|
66
|
-
|
|
67
|
-
### All library defaults
|
|
68
|
-
|
|
69
|
-
Omit every render prop to use built-in puzzle controls and analysis UI. This matches **PuzzleBoardWithControls → All library defaults** in Storybook.
|
|
70
|
-
|
|
71
|
-
```tsx
|
|
72
|
-
import { PuzzleBoardWithControls } from 'react-chess-puzzle-kit';
|
|
73
|
-
|
|
74
|
-
export function PuzzleDemo() {
|
|
75
|
-
return (
|
|
76
|
-
<PuzzleBoardWithControls
|
|
77
|
-
theme="dark"
|
|
78
|
-
apiProxy={{
|
|
79
|
-
onFetch: () => fetchPuzzleFromApi(),
|
|
80
|
-
onFeedback: (data) => sendFeedbackToApi(data),
|
|
81
|
-
}}
|
|
82
|
-
engine={{ enabled: false }}
|
|
83
|
-
/>
|
|
84
|
-
);
|
|
85
|
-
}
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
Defaults used when props are omitted:
|
|
89
|
-
|
|
90
|
-
| Prop | Default |
|
|
91
|
-
|------|---------|
|
|
92
|
-
| `renderControls` | `DefaultPuzzleControls` (hint, next, analysis, result labels) |
|
|
93
|
-
| `renderAnalysis*` | `AnalysisBoard` modal, sidebar, and `EngineEvaluationPanel` |
|
|
94
|
-
| `puzzleBoardWidth` | `DEFAULT_PUZZLE_BOARD_WIDTH` (480) |
|
|
95
|
-
| `analysisLayout` | `DEFAULT_ANALYSIS_LAYOUT` |
|
|
96
|
-
|
|
97
|
-
Reuse the controls alone:
|
|
98
|
-
|
|
99
|
-
```tsx
|
|
100
|
-
import {
|
|
101
|
-
DefaultPuzzleControls,
|
|
102
|
-
defaultRenderControls,
|
|
103
|
-
} from 'react-chess-puzzle-kit';
|
|
104
|
-
|
|
105
|
-
// Inside your own layout:
|
|
106
|
-
<DefaultPuzzleControls
|
|
107
|
-
showHint={showHint}
|
|
108
|
-
nextPuzzle={nextPuzzle}
|
|
109
|
-
resultStatus={resultStatus}
|
|
110
|
-
analysis={analysis}
|
|
111
|
-
/>;
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
In Storybook, the `withDefaultPuzzleControls` decorator does the same for stories that leave `renderControls` unset (see `src/stories/withDefaultPuzzleControls.tsx`).
|
|
115
|
-
|
|
116
|
-
### Custom UI (production)
|
|
117
|
-
|
|
118
|
-
```tsx
|
|
119
|
-
import {
|
|
120
|
-
PuzzleBoardWithControls,
|
|
121
|
-
DEFAULT_ANALYSIS_LAYOUT,
|
|
122
|
-
} from 'react-chess-puzzle-kit';
|
|
123
|
-
|
|
124
|
-
export function PuzzlePage() {
|
|
125
|
-
return (
|
|
126
|
-
<PuzzleBoardWithControls
|
|
127
|
-
theme="dark"
|
|
128
|
-
puzzleBoardWidth={560}
|
|
129
|
-
analysisLayout={DEFAULT_ANALYSIS_LAYOUT}
|
|
130
|
-
apiProxy={{
|
|
131
|
-
onFetch: () => fetchPuzzleFromApi(),
|
|
132
|
-
onFeedback: (data) => sendFeedbackToApi(data),
|
|
133
|
-
}}
|
|
134
|
-
renderControls={(showHint, nextPuzzle, resultStatus, analysis) => (
|
|
135
|
-
<YourControls
|
|
136
|
-
onHint={showHint}
|
|
137
|
-
onNext={nextPuzzle}
|
|
138
|
-
onOpenAnalysis={analysis.openAnalysis}
|
|
139
|
-
canOpenAnalysis={analysis.visible}
|
|
140
|
-
/>
|
|
141
|
-
)}
|
|
142
|
-
renderAnalysisContainer={(props) => <YourAnalysisDialog {...props} />}
|
|
143
|
-
renderAnalysisSidebar={(props) => <YourMoveList {...props} />}
|
|
144
|
-
renderEngineEvaluation={(props) => <YourEnginePanel {...props} />}
|
|
145
|
-
engine={{ depth: 16, multiPv: 2 }}
|
|
146
|
-
/>
|
|
147
|
-
);
|
|
148
|
-
}
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
---
|
|
152
|
-
|
|
153
|
-
## What’s in the package
|
|
154
|
-
|
|
155
|
-
### Puzzle play
|
|
156
|
-
|
|
157
|
-
| Export | Role |
|
|
158
|
-
|--------|------|
|
|
159
|
-
| **`PuzzleBoardWithControls`** | Orchestrates fetch, puzzle board, controls slot, and analysis mode |
|
|
160
|
-
| **`DefaultPuzzleControls`** | Default hint / next / analysis button row |
|
|
161
|
-
| **`defaultRenderControls`** | Render-prop function wired to `DefaultPuzzleControls` |
|
|
162
|
-
| **`PuzzleBoard`** | Draggable puzzle board with correct/incorrect/hint feedback |
|
|
163
|
-
| **`PuzzlePosition`** | FEN + solution line, move index, guess judging |
|
|
164
|
-
| **`analysisSidebarColors`** | Default analysis move-list striping (override in your app) |
|
|
165
|
-
|
|
166
|
-
**From `react-chess-core` (install separately):** `HighlightChessboard`, `ThemeProvider`, `boardSquareHighlightColors`, `useAnalysisEngine`, `formatEvaluation`, `DEFAULT_STOCKFISH_SCRIPT_URL`, etc.
|
|
167
|
-
|
|
168
|
-
### Analysis
|
|
169
|
-
|
|
170
|
-
Analysis is split so apps can use **presets** or go **fully headless**:
|
|
171
|
-
|
|
172
|
-
| Layer | Location | Use when |
|
|
173
|
-
|-------|----------|----------|
|
|
174
|
-
| **Core** | `src/features/analysis/core/` | You want full control of layout and UI |
|
|
175
|
-
| **Defaults** | `src/features/analysis/defaults/` | You want a working modal + sidebar out of the box |
|
|
176
|
-
|
|
177
|
-
| Export | Role |
|
|
178
|
-
|--------|------|
|
|
179
|
-
| **`usePuzzleAnalysis`** | When analysis can open; snapshot of puzzle state |
|
|
180
|
-
| **`useAnalysisBoardModel`** | FEN, ply navigation, history, engine hook, drop handler (no JSX) |
|
|
181
|
-
| **`AnalysisBoardCore`** | Wires model + board; **requires** all `render*` props |
|
|
182
|
-
| **`AnalysisBoard`** | Same as core but fills missing render props with library defaults |
|
|
183
|
-
| **`AnalysisBoardLayout`** | Optional CSS grid: board column + sidebar column |
|
|
184
|
-
| **`AnalysisLayoutConfig`** | `{ boardWidth, sidebarWidth, columnGap }` |
|
|
185
|
-
|
|
186
|
-
### Engine
|
|
187
|
-
|
|
188
|
-
| Export | Package | Role |
|
|
189
|
-
|--------|---------|------|
|
|
190
|
-
| **`useAnalysisEngine`**, eval helpers | `react-chess-core` | Stockfish hook + PV formatting |
|
|
191
|
-
| **`EngineEvaluationPanel`** | puzzle-kit | Default engine UI (`AnalysisBoard` preset) |
|
|
192
|
-
|
|
193
|
-
---
|
|
194
|
-
|
|
195
|
-
## Architecture
|
|
196
|
-
|
|
197
|
-
```
|
|
198
|
-
┌─────────────────────────────────────────────────────────────┐
|
|
199
|
-
│ PuzzleBoardWithControls (host app) │
|
|
200
|
-
│ ├─ puzzle play → PuzzleBoard (puzzleBoardWidth) │
|
|
201
|
-
│ └─ analysis open → AnalysisBoardCore | AnalysisBoard │
|
|
202
|
-
│ ├─ renderContainer (modal / page shell) │
|
|
203
|
-
│ ├─ renderMain (board + sidebar placement) │
|
|
204
|
-
│ ├─ renderSidebar (move list, nav) │
|
|
205
|
-
│ └─ renderEngineEvaluation (Stockfish lines) │
|
|
206
|
-
└─────────────────────────────────────────────────────────────┘
|
|
207
|
-
```
|
|
208
|
-
|
|
209
|
-
**Separation of concerns**
|
|
210
|
-
|
|
211
|
-
- **Logic** — puzzle position, analysis context, ply navigation (`analysis/core/`); engine hook from **`react-chess-core`**.
|
|
212
|
-
- **UI** — host render props, or `defaults/` (`AnalysisBoard`, `DefaultAnalysisSidebar`, `DefaultAnalysisContainer`, `EngineEvaluationPanel`).
|
|
213
|
-
|
|
214
|
-
Production apps (e.g. endchess-frontend) typically pass custom `renderAnalysis*` implementations and sizes via `puzzleBoardWidth` + `analysisLayout`, while reusing `useAnalysisBoardModel` behavior through `AnalysisBoardCore`.
|
|
215
|
-
|
|
216
|
-
---
|
|
217
|
-
|
|
218
|
-
## Board sizing
|
|
219
|
-
|
|
220
|
-
Puzzle and analysis boards can use **different pixel widths**:
|
|
221
|
-
|
|
222
|
-
```tsx
|
|
223
|
-
<PuzzleBoardWithControls
|
|
224
|
-
puzzleBoardWidth={560} // live puzzle
|
|
225
|
-
analysisLayout={{
|
|
226
|
-
boardWidth: 480, // analysis chessboard
|
|
227
|
-
sidebarWidth: 500,
|
|
228
|
-
columnGap: 16,
|
|
229
|
-
}}
|
|
230
|
-
/>
|
|
231
|
-
```
|
|
232
|
-
|
|
233
|
-
Defaults: `DEFAULT_PUZZLE_BOARD_WIDTH` (480) and `DEFAULT_ANALYSIS_LAYOUT`. Override `renderAnalysisMain` for a fully custom layout (flex, MUI grid, etc.).
|
|
234
|
-
|
|
235
|
-
---
|
|
236
|
-
|
|
237
|
-
## Stockfish (browser engine)
|
|
238
|
-
|
|
239
|
-
Analysis runs Stockfish in a **Web Worker**. The host must serve the engine assets:
|
|
240
|
-
|
|
241
|
-
```bash
|
|
242
|
-
npm install stockfish --save-optional # or a regular dependency
|
|
243
|
-
npm run copy:stockfish # copies to public/stockfish/ in this repo
|
|
244
|
-
```
|
|
245
|
-
|
|
246
|
-
In your app, copy the same files to `public/stockfish/` (or equivalent). Default script URL:
|
|
247
|
-
|
|
248
|
-
`/stockfish/stockfish-18-lite-single.js` (`.wasm` must sit beside it).
|
|
249
|
-
|
|
250
|
-
```tsx
|
|
251
|
-
<PuzzleBoardWithControls
|
|
252
|
-
engine={{
|
|
253
|
-
enabled: true,
|
|
254
|
-
depth: 18,
|
|
255
|
-
multiPv: 2,
|
|
256
|
-
scriptUrl: '/stockfish/stockfish-18-lite-single.js',
|
|
257
|
-
}}
|
|
258
|
-
/>
|
|
259
|
-
```
|
|
260
|
-
|
|
261
|
-
Disable the worker when you only need move replay: `engine={{ enabled: false }}`.
|
|
262
|
-
|
|
263
|
-
---
|
|
264
|
-
|
|
265
|
-
## Headless analysis example
|
|
266
|
-
|
|
267
|
-
Use `AnalysisBoardCore` when every visual piece comes from the host:
|
|
268
|
-
|
|
269
|
-
```tsx
|
|
270
|
-
import {
|
|
271
|
-
AnalysisBoardCore,
|
|
272
|
-
AnalysisBoardLayout,
|
|
273
|
-
DEFAULT_ANALYSIS_LAYOUT,
|
|
274
|
-
} from 'react-chess-puzzle-kit';
|
|
275
|
-
|
|
276
|
-
<AnalysisBoardCore
|
|
277
|
-
analysisContext={snapshot}
|
|
278
|
-
theme="dark"
|
|
279
|
-
boardWidth={layout.boardWidth}
|
|
280
|
-
onClose={close}
|
|
281
|
-
renderContainer={(p) => <MyDialog {...p} />}
|
|
282
|
-
renderMain={({ board, sidebar, model }) => (
|
|
283
|
-
<AnalysisBoardLayout layout={layout} model={model} board={board} sidebar={sidebar} />
|
|
284
|
-
)}
|
|
285
|
-
renderSidebar={(p) => <MySidebar {...p} />}
|
|
286
|
-
renderEngineEvaluation={(p) => <MyEngine {...p} />}
|
|
287
|
-
/>;
|
|
288
|
-
```
|
|
289
|
-
|
|
290
|
-
---
|
|
291
|
-
|
|
292
|
-
## Development
|
|
293
|
-
|
|
294
|
-
```bash
|
|
295
|
-
npm run build # Rollup → dist/
|
|
296
|
-
npm run storybook # component docs & examples
|
|
297
|
-
npm run build-storybook # static Storybook export
|
|
298
|
-
npm run copy:stockfish # engine binaries for local Storybook
|
|
299
|
-
```
|
|
300
|
-
|
|
301
|
-
---
|
|
302
|
-
|
|
303
|
-
## Migration: engine/board imports
|
|
304
|
-
|
|
305
|
-
If you previously imported these from `react-chess-puzzle-kit`, switch to `react-chess-core`:
|
|
306
|
-
|
|
307
|
-
```diff
|
|
308
|
-
- import { useAnalysisEngine, formatEvaluation, ThemeProvider } from 'react-chess-puzzle-kit';
|
|
309
|
-
+ import { useAnalysisEngine, formatEvaluation, ThemeProvider } from 'react-chess-core';
|
|
310
|
-
```
|
|
311
|
-
|
|
312
|
-
Keep puzzle-specific imports on puzzle-kit (`PuzzleBoardWithControls`, `usePuzzleAnalysis`, `AnalysisBoardCore`, render-prop types, etc.).
|
|
313
|
-
|
|
314
|
-
---
|
|
315
|
-
|
|
316
|
-
## Migration from `react-chessboard-with-controls`
|
|
317
|
-
|
|
318
|
-
The package was renamed to **`react-chess-puzzle-kit`** (v1.0.0). Update imports:
|
|
319
|
-
|
|
320
|
-
```diff
|
|
321
|
-
- import { PuzzleBoardWithControls } from 'react-chessboard-with-controls';
|
|
322
|
-
+ import { PuzzleBoardWithControls } from 'react-chess-puzzle-kit';
|
|
323
|
-
```
|
|
324
|
-
|
|
325
|
-
Component export names are unchanged for now. Rename the local clone folder to `react-chess-puzzle-kit` and point `file:../react-chess-puzzle-kit` in consuming apps.
|
|
326
|
-
|
|
327
|
-
---
|
|
328
|
-
|
|
329
|
-
## License
|
|
330
|
-
|
|
331
|
-
MIT © 2022–2026 Robert Blackwell
|
|
1
|
+
# react-chess-puzzle-kit
|
|
2
|
+
|
|
3
|
+
```bash
|
|
4
|
+
npm install
|
|
5
|
+
npm run build
|
|
6
|
+
```
|
|
7
|
+
|
|
8
|
+
Build output: `dist/` (`index.js`, `index.esm.js`, `index.d.ts`). Re-run after source changes when consuming this package via `file:../react-chess-puzzle-kit`.
|
|
9
|
+
|
|
10
|
+
React components for **interactive chess puzzles** and **post-puzzle analysis**, built on [react-chessboard](https://github.com/Clariity/react-chessboard) and [chess.js](https://github.com/jhlywa/chess.js). Used in production at [endchess.com](https://endchess.com).
|
|
11
|
+
|
|
12
|
+
The library owns puzzle logic, move history, themes, and optional Stockfish analysis. **Defaults are included** for a full demo (controls + analysis UI); production apps usually replace those with custom render props.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Install
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install react-chess-puzzle-kit
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
**Peer dependencies:** `react`, `react-chessboard`, `chess.js`, **`react-chess-core`** (required — see `package.json`).
|
|
23
|
+
|
|
24
|
+
Install both packages in your app:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npm install react-chess-puzzle-kit react-chess-core
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Local development: `file:../react-chess-core` and `file:../react-chess-puzzle-kit` — build core first (`npm run build` in that repo), then puzzle-kit, then `npm install` in the app.
|
|
31
|
+
|
|
32
|
+
**Board theme, `HighlightChessboard`, Stockfish hooks, and eval formatters** are exported from **`react-chess-core`**, not re-exported from puzzle-kit. Puzzle-kit covers puzzle play, analysis orchestration, and optional default analysis UI.
|
|
33
|
+
|
|
34
|
+
For engine analysis in the browser, also install Stockfish and copy WASM into your app’s static folder (see [Stockfish](#stockfish-browser-engine) below).
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## See it in action (Storybook)
|
|
39
|
+
|
|
40
|
+
Storybook is the living docs and playground for every export.
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
git clone https://github.com/reblackwell3/react-chess-puzzle-kit.git
|
|
44
|
+
cd react-chess-puzzle-kit
|
|
45
|
+
npm install
|
|
46
|
+
npm run storybook # http://localhost:6006
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
| Story | What it demonstrates |
|
|
50
|
+
|-------|----------------------|
|
|
51
|
+
| **PuzzleBoardWithControls** | Full puzzle flow with default controls (via decorator) |
|
|
52
|
+
| **PuzzleBoardWithControls → All library defaults** | Default controls + default analysis modal, sidebar, engine panel |
|
|
53
|
+
| **PuzzleBoard** | Puzzle board only (drag-and-drop, feedback highlights) |
|
|
54
|
+
| **Analysis / AnalysisBoard (defaults)** | Default modal, sidebar, grid, and engine panel |
|
|
55
|
+
| **HighlightChessboard** | Themed board with check / hint / incorrect square styles |
|
|
56
|
+
|
|
57
|
+
Optional: `npm run copy:stockfish` then open **Analysis → WithStockfishEngine** to exercise the worker.
|
|
58
|
+
|
|
59
|
+
Build a static catalog: `npm run build-storybook` → `npm run serve-storybook`.
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Quick start
|
|
64
|
+
|
|
65
|
+
`PuzzleBoardWithControls` is the main integration point: puzzle play, then analysis when the puzzle is finished or failed.
|
|
66
|
+
|
|
67
|
+
### All library defaults
|
|
68
|
+
|
|
69
|
+
Omit every render prop to use built-in puzzle controls and analysis UI. This matches **PuzzleBoardWithControls → All library defaults** in Storybook.
|
|
70
|
+
|
|
71
|
+
```tsx
|
|
72
|
+
import { PuzzleBoardWithControls } from 'react-chess-puzzle-kit';
|
|
73
|
+
|
|
74
|
+
export function PuzzleDemo() {
|
|
75
|
+
return (
|
|
76
|
+
<PuzzleBoardWithControls
|
|
77
|
+
theme="dark"
|
|
78
|
+
apiProxy={{
|
|
79
|
+
onFetch: () => fetchPuzzleFromApi(),
|
|
80
|
+
onFeedback: (data) => sendFeedbackToApi(data),
|
|
81
|
+
}}
|
|
82
|
+
engine={{ enabled: false }}
|
|
83
|
+
/>
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Defaults used when props are omitted:
|
|
89
|
+
|
|
90
|
+
| Prop | Default |
|
|
91
|
+
|------|---------|
|
|
92
|
+
| `renderControls` | `DefaultPuzzleControls` (hint, next, analysis, result labels) |
|
|
93
|
+
| `renderAnalysis*` | `AnalysisBoard` modal, sidebar, and `EngineEvaluationPanel` |
|
|
94
|
+
| `puzzleBoardWidth` | `DEFAULT_PUZZLE_BOARD_WIDTH` (480) |
|
|
95
|
+
| `analysisLayout` | `DEFAULT_ANALYSIS_LAYOUT` |
|
|
96
|
+
|
|
97
|
+
Reuse the controls alone:
|
|
98
|
+
|
|
99
|
+
```tsx
|
|
100
|
+
import {
|
|
101
|
+
DefaultPuzzleControls,
|
|
102
|
+
defaultRenderControls,
|
|
103
|
+
} from 'react-chess-puzzle-kit';
|
|
104
|
+
|
|
105
|
+
// Inside your own layout:
|
|
106
|
+
<DefaultPuzzleControls
|
|
107
|
+
showHint={showHint}
|
|
108
|
+
nextPuzzle={nextPuzzle}
|
|
109
|
+
resultStatus={resultStatus}
|
|
110
|
+
analysis={analysis}
|
|
111
|
+
/>;
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
In Storybook, the `withDefaultPuzzleControls` decorator does the same for stories that leave `renderControls` unset (see `src/stories/withDefaultPuzzleControls.tsx`).
|
|
115
|
+
|
|
116
|
+
### Custom UI (production)
|
|
117
|
+
|
|
118
|
+
```tsx
|
|
119
|
+
import {
|
|
120
|
+
PuzzleBoardWithControls,
|
|
121
|
+
DEFAULT_ANALYSIS_LAYOUT,
|
|
122
|
+
} from 'react-chess-puzzle-kit';
|
|
123
|
+
|
|
124
|
+
export function PuzzlePage() {
|
|
125
|
+
return (
|
|
126
|
+
<PuzzleBoardWithControls
|
|
127
|
+
theme="dark"
|
|
128
|
+
puzzleBoardWidth={560}
|
|
129
|
+
analysisLayout={DEFAULT_ANALYSIS_LAYOUT}
|
|
130
|
+
apiProxy={{
|
|
131
|
+
onFetch: () => fetchPuzzleFromApi(),
|
|
132
|
+
onFeedback: (data) => sendFeedbackToApi(data),
|
|
133
|
+
}}
|
|
134
|
+
renderControls={(showHint, nextPuzzle, resultStatus, analysis) => (
|
|
135
|
+
<YourControls
|
|
136
|
+
onHint={showHint}
|
|
137
|
+
onNext={nextPuzzle}
|
|
138
|
+
onOpenAnalysis={analysis.openAnalysis}
|
|
139
|
+
canOpenAnalysis={analysis.visible}
|
|
140
|
+
/>
|
|
141
|
+
)}
|
|
142
|
+
renderAnalysisContainer={(props) => <YourAnalysisDialog {...props} />}
|
|
143
|
+
renderAnalysisSidebar={(props) => <YourMoveList {...props} />}
|
|
144
|
+
renderEngineEvaluation={(props) => <YourEnginePanel {...props} />}
|
|
145
|
+
engine={{ depth: 16, multiPv: 2 }}
|
|
146
|
+
/>
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## What’s in the package
|
|
154
|
+
|
|
155
|
+
### Puzzle play
|
|
156
|
+
|
|
157
|
+
| Export | Role |
|
|
158
|
+
|--------|------|
|
|
159
|
+
| **`PuzzleBoardWithControls`** | Orchestrates fetch, puzzle board, controls slot, and analysis mode |
|
|
160
|
+
| **`DefaultPuzzleControls`** | Default hint / next / analysis button row |
|
|
161
|
+
| **`defaultRenderControls`** | Render-prop function wired to `DefaultPuzzleControls` |
|
|
162
|
+
| **`PuzzleBoard`** | Draggable puzzle board with correct/incorrect/hint feedback |
|
|
163
|
+
| **`PuzzlePosition`** | FEN + solution line, move index, guess judging |
|
|
164
|
+
| **`analysisSidebarColors`** | Default analysis move-list striping (override in your app) |
|
|
165
|
+
|
|
166
|
+
**From `react-chess-core` (install separately):** `HighlightChessboard`, `ThemeProvider`, `boardSquareHighlightColors`, `useAnalysisEngine`, `formatEvaluation`, `DEFAULT_STOCKFISH_SCRIPT_URL`, etc.
|
|
167
|
+
|
|
168
|
+
### Analysis
|
|
169
|
+
|
|
170
|
+
Analysis is split so apps can use **presets** or go **fully headless**:
|
|
171
|
+
|
|
172
|
+
| Layer | Location | Use when |
|
|
173
|
+
|-------|----------|----------|
|
|
174
|
+
| **Core** | `src/features/analysis/core/` | You want full control of layout and UI |
|
|
175
|
+
| **Defaults** | `src/features/analysis/defaults/` | You want a working modal + sidebar out of the box |
|
|
176
|
+
|
|
177
|
+
| Export | Role |
|
|
178
|
+
|--------|------|
|
|
179
|
+
| **`usePuzzleAnalysis`** | When analysis can open; snapshot of puzzle state |
|
|
180
|
+
| **`useAnalysisBoardModel`** | FEN, ply navigation, history, engine hook, drop handler (no JSX) |
|
|
181
|
+
| **`AnalysisBoardCore`** | Wires model + board; **requires** all `render*` props |
|
|
182
|
+
| **`AnalysisBoard`** | Same as core but fills missing render props with library defaults |
|
|
183
|
+
| **`AnalysisBoardLayout`** | Optional CSS grid: board column + sidebar column |
|
|
184
|
+
| **`AnalysisLayoutConfig`** | `{ boardWidth, sidebarWidth, columnGap }` |
|
|
185
|
+
|
|
186
|
+
### Engine
|
|
187
|
+
|
|
188
|
+
| Export | Package | Role |
|
|
189
|
+
|--------|---------|------|
|
|
190
|
+
| **`useAnalysisEngine`**, eval helpers | `react-chess-core` | Stockfish hook + PV formatting |
|
|
191
|
+
| **`EngineEvaluationPanel`** | puzzle-kit | Default engine UI (`AnalysisBoard` preset) |
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## Architecture
|
|
196
|
+
|
|
197
|
+
```
|
|
198
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
199
|
+
│ PuzzleBoardWithControls (host app) │
|
|
200
|
+
│ ├─ puzzle play → PuzzleBoard (puzzleBoardWidth) │
|
|
201
|
+
│ └─ analysis open → AnalysisBoardCore | AnalysisBoard │
|
|
202
|
+
│ ├─ renderContainer (modal / page shell) │
|
|
203
|
+
│ ├─ renderMain (board + sidebar placement) │
|
|
204
|
+
│ ├─ renderSidebar (move list, nav) │
|
|
205
|
+
│ └─ renderEngineEvaluation (Stockfish lines) │
|
|
206
|
+
└─────────────────────────────────────────────────────────────┘
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
**Separation of concerns**
|
|
210
|
+
|
|
211
|
+
- **Logic** — puzzle position, analysis context, ply navigation (`analysis/core/`); engine hook from **`react-chess-core`**.
|
|
212
|
+
- **UI** — host render props, or `defaults/` (`AnalysisBoard`, `DefaultAnalysisSidebar`, `DefaultAnalysisContainer`, `EngineEvaluationPanel`).
|
|
213
|
+
|
|
214
|
+
Production apps (e.g. endchess-frontend) typically pass custom `renderAnalysis*` implementations and sizes via `puzzleBoardWidth` + `analysisLayout`, while reusing `useAnalysisBoardModel` behavior through `AnalysisBoardCore`.
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## Board sizing
|
|
219
|
+
|
|
220
|
+
Puzzle and analysis boards can use **different pixel widths**:
|
|
221
|
+
|
|
222
|
+
```tsx
|
|
223
|
+
<PuzzleBoardWithControls
|
|
224
|
+
puzzleBoardWidth={560} // live puzzle
|
|
225
|
+
analysisLayout={{
|
|
226
|
+
boardWidth: 480, // analysis chessboard
|
|
227
|
+
sidebarWidth: 500,
|
|
228
|
+
columnGap: 16,
|
|
229
|
+
}}
|
|
230
|
+
/>
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
Defaults: `DEFAULT_PUZZLE_BOARD_WIDTH` (480) and `DEFAULT_ANALYSIS_LAYOUT`. Override `renderAnalysisMain` for a fully custom layout (flex, MUI grid, etc.).
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
## Stockfish (browser engine)
|
|
238
|
+
|
|
239
|
+
Analysis runs Stockfish in a **Web Worker**. The host must serve the engine assets:
|
|
240
|
+
|
|
241
|
+
```bash
|
|
242
|
+
npm install stockfish --save-optional # or a regular dependency
|
|
243
|
+
npm run copy:stockfish # copies to public/stockfish/ in this repo
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
In your app, copy the same files to `public/stockfish/` (or equivalent). Default script URL:
|
|
247
|
+
|
|
248
|
+
`/stockfish/stockfish-18-lite-single.js` (`.wasm` must sit beside it).
|
|
249
|
+
|
|
250
|
+
```tsx
|
|
251
|
+
<PuzzleBoardWithControls
|
|
252
|
+
engine={{
|
|
253
|
+
enabled: true,
|
|
254
|
+
depth: 18,
|
|
255
|
+
multiPv: 2,
|
|
256
|
+
scriptUrl: '/stockfish/stockfish-18-lite-single.js',
|
|
257
|
+
}}
|
|
258
|
+
/>
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
Disable the worker when you only need move replay: `engine={{ enabled: false }}`.
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
265
|
+
## Headless analysis example
|
|
266
|
+
|
|
267
|
+
Use `AnalysisBoardCore` when every visual piece comes from the host:
|
|
268
|
+
|
|
269
|
+
```tsx
|
|
270
|
+
import {
|
|
271
|
+
AnalysisBoardCore,
|
|
272
|
+
AnalysisBoardLayout,
|
|
273
|
+
DEFAULT_ANALYSIS_LAYOUT,
|
|
274
|
+
} from 'react-chess-puzzle-kit';
|
|
275
|
+
|
|
276
|
+
<AnalysisBoardCore
|
|
277
|
+
analysisContext={snapshot}
|
|
278
|
+
theme="dark"
|
|
279
|
+
boardWidth={layout.boardWidth}
|
|
280
|
+
onClose={close}
|
|
281
|
+
renderContainer={(p) => <MyDialog {...p} />}
|
|
282
|
+
renderMain={({ board, sidebar, model }) => (
|
|
283
|
+
<AnalysisBoardLayout layout={layout} model={model} board={board} sidebar={sidebar} />
|
|
284
|
+
)}
|
|
285
|
+
renderSidebar={(p) => <MySidebar {...p} />}
|
|
286
|
+
renderEngineEvaluation={(p) => <MyEngine {...p} />}
|
|
287
|
+
/>;
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
---
|
|
291
|
+
|
|
292
|
+
## Development
|
|
293
|
+
|
|
294
|
+
```bash
|
|
295
|
+
npm run build # Rollup → dist/
|
|
296
|
+
npm run storybook # component docs & examples
|
|
297
|
+
npm run build-storybook # static Storybook export
|
|
298
|
+
npm run copy:stockfish # engine binaries for local Storybook
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
---
|
|
302
|
+
|
|
303
|
+
## Migration: engine/board imports
|
|
304
|
+
|
|
305
|
+
If you previously imported these from `react-chess-puzzle-kit`, switch to `react-chess-core`:
|
|
306
|
+
|
|
307
|
+
```diff
|
|
308
|
+
- import { useAnalysisEngine, formatEvaluation, ThemeProvider } from 'react-chess-puzzle-kit';
|
|
309
|
+
+ import { useAnalysisEngine, formatEvaluation, ThemeProvider } from 'react-chess-core';
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
Keep puzzle-specific imports on puzzle-kit (`PuzzleBoardWithControls`, `usePuzzleAnalysis`, `AnalysisBoardCore`, render-prop types, etc.).
|
|
313
|
+
|
|
314
|
+
---
|
|
315
|
+
|
|
316
|
+
## Migration from `react-chessboard-with-controls`
|
|
317
|
+
|
|
318
|
+
The package was renamed to **`react-chess-puzzle-kit`** (v1.0.0). Update imports:
|
|
319
|
+
|
|
320
|
+
```diff
|
|
321
|
+
- import { PuzzleBoardWithControls } from 'react-chessboard-with-controls';
|
|
322
|
+
+ import { PuzzleBoardWithControls } from 'react-chess-puzzle-kit';
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
Component export names are unchanged for now. Rename the local clone folder to `react-chess-puzzle-kit` and point `file:../react-chess-puzzle-kit` in consuming apps.
|
|
326
|
+
|
|
327
|
+
---
|
|
328
|
+
|
|
329
|
+
## License
|
|
330
|
+
|
|
331
|
+
MIT © 2022–2026 Robert Blackwell
|
package/dist/index.esm.js
CHANGED
|
@@ -65,6 +65,7 @@ const PuzzlePlaySurface = ({ position, onFeedback, incInteractionNum, boardWidth
|
|
|
65
65
|
var _a, _b, _c, _d, _e, _f, _g;
|
|
66
66
|
const [showAnswerArrow, setShowAnswerArrow] = useState(false);
|
|
67
67
|
const [incorrectActive, setIncorrectActive] = useState(false);
|
|
68
|
+
const attemptMissedRef = useRef(false);
|
|
68
69
|
const { revision, bumpRevision } = useBoardRevision();
|
|
69
70
|
const boardOrientationRef = useRef('white');
|
|
70
71
|
const boardFenRef = useRef(EMPTY_BOARD_FEN);
|
|
@@ -101,6 +102,7 @@ const PuzzlePlaySurface = ({ position, onFeedback, incInteractionNum, boardWidth
|
|
|
101
102
|
useEffect(() => {
|
|
102
103
|
setShowAnswerArrow(false);
|
|
103
104
|
setIncorrectActive(false);
|
|
105
|
+
attemptMissedRef.current = false;
|
|
104
106
|
onMissFeedbackChange === null || onMissFeedbackChange === void 0 ? void 0 : onMissFeedbackChange(null);
|
|
105
107
|
}, [onMissFeedbackChange, position]);
|
|
106
108
|
useEffect(() => {
|
|
@@ -182,6 +184,7 @@ const PuzzlePlaySurface = ({ position, onFeedback, incInteractionNum, boardWidth
|
|
|
182
184
|
recordIfIncorrect: !(answerArrowVisible && !allowRetryOnIncorrect),
|
|
183
185
|
});
|
|
184
186
|
if (!guess.accepted) {
|
|
187
|
+
attemptMissedRef.current = true;
|
|
185
188
|
onFeedback({
|
|
186
189
|
index: position.getIndex(),
|
|
187
190
|
guess: { sourceSquare, targetSquare, piece },
|
|
@@ -224,12 +227,21 @@ const PuzzlePlaySurface = ({ position, onFeedback, incInteractionNum, boardWidth
|
|
|
224
227
|
setIncorrectActive(false);
|
|
225
228
|
missBoard.missSequence.clearSequence();
|
|
226
229
|
onMissFeedbackChange === null || onMissFeedbackChange === void 0 ? void 0 : onMissFeedbackChange(null);
|
|
227
|
-
|
|
230
|
+
const assistedByAnswerArrow = answerArrowVisible && attemptMissedRef.current;
|
|
231
|
+
const guessPayload = {
|
|
228
232
|
index: position.getIndex(),
|
|
229
233
|
guess: { sourceSquare, targetSquare, piece },
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
234
|
+
};
|
|
235
|
+
if (assistedByAnswerArrow) {
|
|
236
|
+
// Miss feedback for this ply is already saved; dragging along the answer
|
|
237
|
+
// arrow only continues the line — it must not count as a clean solve.
|
|
238
|
+
if (guess.finished) {
|
|
239
|
+
onFeedback(Object.assign(Object.assign({}, guessPayload), { isCorrect: false, isFinished: true }));
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
else {
|
|
243
|
+
onFeedback(Object.assign(Object.assign({}, guessPayload), { isCorrect: true, isFinished: guess.finished }));
|
|
244
|
+
}
|
|
233
245
|
notifyHost();
|
|
234
246
|
setTimeout(() => {
|
|
235
247
|
position.resetInteractions();
|
package/dist/index.js
CHANGED
|
@@ -66,6 +66,7 @@ const PuzzlePlaySurface = ({ position, onFeedback, incInteractionNum, boardWidth
|
|
|
66
66
|
var _a, _b, _c, _d, _e, _f, _g;
|
|
67
67
|
const [showAnswerArrow, setShowAnswerArrow] = react.useState(false);
|
|
68
68
|
const [incorrectActive, setIncorrectActive] = react.useState(false);
|
|
69
|
+
const attemptMissedRef = react.useRef(false);
|
|
69
70
|
const { revision, bumpRevision } = reactChessCore.useBoardRevision();
|
|
70
71
|
const boardOrientationRef = react.useRef('white');
|
|
71
72
|
const boardFenRef = react.useRef(EMPTY_BOARD_FEN);
|
|
@@ -102,6 +103,7 @@ const PuzzlePlaySurface = ({ position, onFeedback, incInteractionNum, boardWidth
|
|
|
102
103
|
react.useEffect(() => {
|
|
103
104
|
setShowAnswerArrow(false);
|
|
104
105
|
setIncorrectActive(false);
|
|
106
|
+
attemptMissedRef.current = false;
|
|
105
107
|
onMissFeedbackChange === null || onMissFeedbackChange === void 0 ? void 0 : onMissFeedbackChange(null);
|
|
106
108
|
}, [onMissFeedbackChange, position]);
|
|
107
109
|
react.useEffect(() => {
|
|
@@ -183,6 +185,7 @@ const PuzzlePlaySurface = ({ position, onFeedback, incInteractionNum, boardWidth
|
|
|
183
185
|
recordIfIncorrect: !(answerArrowVisible && !allowRetryOnIncorrect),
|
|
184
186
|
});
|
|
185
187
|
if (!guess.accepted) {
|
|
188
|
+
attemptMissedRef.current = true;
|
|
186
189
|
onFeedback({
|
|
187
190
|
index: position.getIndex(),
|
|
188
191
|
guess: { sourceSquare, targetSquare, piece },
|
|
@@ -225,12 +228,21 @@ const PuzzlePlaySurface = ({ position, onFeedback, incInteractionNum, boardWidth
|
|
|
225
228
|
setIncorrectActive(false);
|
|
226
229
|
missBoard.missSequence.clearSequence();
|
|
227
230
|
onMissFeedbackChange === null || onMissFeedbackChange === void 0 ? void 0 : onMissFeedbackChange(null);
|
|
228
|
-
|
|
231
|
+
const assistedByAnswerArrow = answerArrowVisible && attemptMissedRef.current;
|
|
232
|
+
const guessPayload = {
|
|
229
233
|
index: position.getIndex(),
|
|
230
234
|
guess: { sourceSquare, targetSquare, piece },
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
235
|
+
};
|
|
236
|
+
if (assistedByAnswerArrow) {
|
|
237
|
+
// Miss feedback for this ply is already saved; dragging along the answer
|
|
238
|
+
// arrow only continues the line — it must not count as a clean solve.
|
|
239
|
+
if (guess.finished) {
|
|
240
|
+
onFeedback(Object.assign(Object.assign({}, guessPayload), { isCorrect: false, isFinished: true }));
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
else {
|
|
244
|
+
onFeedback(Object.assign(Object.assign({}, guessPayload), { isCorrect: true, isFinished: guess.finished }));
|
|
245
|
+
}
|
|
234
246
|
notifyHost();
|
|
235
247
|
setTimeout(() => {
|
|
236
248
|
position.resetInteractions();
|
package/package.json
CHANGED
|
@@ -1,87 +1,87 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "react-chess-puzzle-kit",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "React chess puzzle kit: play, controls, analysis, and browser Stockfish for endchess.training and other apps",
|
|
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-puzzle-kit.git"
|
|
13
|
-
},
|
|
14
|
-
"bugs": {
|
|
15
|
-
"url": "https://github.com/reblackwell3/react-chess-puzzle-kit/issues"
|
|
16
|
-
},
|
|
17
|
-
"homepage": "https://github.com/reblackwell3/react-chess-puzzle-kit#readme",
|
|
18
|
-
"keywords": [
|
|
19
|
-
"react",
|
|
20
|
-
"chess",
|
|
21
|
-
"chess.js",
|
|
22
|
-
"chess puzzle",
|
|
23
|
-
"puzzle",
|
|
24
|
-
"analysis",
|
|
25
|
-
"stockfish",
|
|
26
|
-
"react-chessboard",
|
|
27
|
-
"chessboard",
|
|
28
|
-
"drag and drop"
|
|
29
|
-
],
|
|
30
|
-
"files": [
|
|
31
|
-
"dist"
|
|
32
|
-
],
|
|
33
|
-
"scripts": {
|
|
34
|
-
"build": "rollup -c",
|
|
35
|
-
"copy:stockfish": "node scripts/copy-stockfish.mjs",
|
|
36
|
-
"prepare": "rollup -c",
|
|
37
|
-
"prestorybook": "npm run copy:stockfish",
|
|
38
|
-
"test": "jest --config jest.config.cjs",
|
|
39
|
-
"storybook": "storybook dev -p 6006",
|
|
40
|
-
"build-storybook": "storybook build",
|
|
41
|
-
"serve-storybook": "serve storybook-static",
|
|
42
|
-
"prepublishOnly": "npm run build"
|
|
43
|
-
},
|
|
44
|
-
"dependencies": {
|
|
45
|
-
"chess.js": "^1.0.0-beta.8",
|
|
46
|
-
"rollup": "^4.22.2",
|
|
47
|
-
"rollup-plugin-peer-deps-external": "^2.2.4",
|
|
48
|
-
"rollup-plugin-typescript2": "^0.36.0",
|
|
49
|
-
"typescript": "^5.6.2"
|
|
50
|
-
},
|
|
51
|
-
"peerDependencies": {
|
|
52
|
-
"chess.js": "^1.0.0-beta.8",
|
|
53
|
-
"react": "^18.3.1",
|
|
54
|
-
"react-chess-core": "^0.1.1",
|
|
55
|
-
"react-chessboard": "^4.7.1"
|
|
56
|
-
},
|
|
57
|
-
"devDependencies": {
|
|
58
|
-
"@chromatic-com/storybook": "^1.9.0",
|
|
59
|
-
"@rollup/plugin-commonjs": "^26.0.1",
|
|
60
|
-
"@rollup/plugin-node-resolve": "^15.2.3",
|
|
61
|
-
"@rollup/plugin-terser": "^0.4.4",
|
|
62
|
-
"@storybook/addon-essentials": "^8.2.9",
|
|
63
|
-
"@storybook/addon-interactions": "^8.2.9",
|
|
64
|
-
"@storybook/addon-links": "^8.2.9",
|
|
65
|
-
"@storybook/addon-onboarding": "^8.2.9",
|
|
66
|
-
"@storybook/blocks": "^8.2.9",
|
|
67
|
-
"@storybook/preset-typescript": "^3.0.0",
|
|
68
|
-
"@storybook/react": "^8.2.9",
|
|
69
|
-
"@storybook/react-vite": "^8.2.9",
|
|
70
|
-
"@storybook/test": "^8.2.9",
|
|
71
|
-
"@types/jest": "^29.5.12",
|
|
72
|
-
"@types/react": "^18.3.12",
|
|
73
|
-
"@types/react-dom": "^18.3.1",
|
|
74
|
-
"chess.js": "^1.0.0-beta.8",
|
|
75
|
-
"jest": "^29.7.0",
|
|
76
|
-
"react": "^18.3.1",
|
|
77
|
-
"react-chess-core": "^0.1.1",
|
|
78
|
-
"react-chessboard": "^4.7.1",
|
|
79
|
-
"storybook": "^8.2.9",
|
|
80
|
-
"ts-jest": "^29.2.4",
|
|
81
|
-
"vite": "^5.4.11",
|
|
82
|
-
"vite-tsconfig-paths": "^5.0.1"
|
|
83
|
-
},
|
|
84
|
-
"optionalDependencies": {
|
|
85
|
-
"stockfish": "^18.0.7"
|
|
86
|
-
}
|
|
87
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "react-chess-puzzle-kit",
|
|
3
|
+
"version": "1.0.2",
|
|
4
|
+
"description": "React chess puzzle kit: play, controls, analysis, and browser Stockfish for endchess.training and other apps",
|
|
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-puzzle-kit.git"
|
|
13
|
+
},
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://github.com/reblackwell3/react-chess-puzzle-kit/issues"
|
|
16
|
+
},
|
|
17
|
+
"homepage": "https://github.com/reblackwell3/react-chess-puzzle-kit#readme",
|
|
18
|
+
"keywords": [
|
|
19
|
+
"react",
|
|
20
|
+
"chess",
|
|
21
|
+
"chess.js",
|
|
22
|
+
"chess puzzle",
|
|
23
|
+
"puzzle",
|
|
24
|
+
"analysis",
|
|
25
|
+
"stockfish",
|
|
26
|
+
"react-chessboard",
|
|
27
|
+
"chessboard",
|
|
28
|
+
"drag and drop"
|
|
29
|
+
],
|
|
30
|
+
"files": [
|
|
31
|
+
"dist"
|
|
32
|
+
],
|
|
33
|
+
"scripts": {
|
|
34
|
+
"build": "rollup -c",
|
|
35
|
+
"copy:stockfish": "node scripts/copy-stockfish.mjs",
|
|
36
|
+
"prepare": "rollup -c",
|
|
37
|
+
"prestorybook": "npm run copy:stockfish",
|
|
38
|
+
"test": "jest --config jest.config.cjs",
|
|
39
|
+
"storybook": "storybook dev -p 6006",
|
|
40
|
+
"build-storybook": "storybook build",
|
|
41
|
+
"serve-storybook": "serve storybook-static",
|
|
42
|
+
"prepublishOnly": "npm run build"
|
|
43
|
+
},
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"chess.js": "^1.0.0-beta.8",
|
|
46
|
+
"rollup": "^4.22.2",
|
|
47
|
+
"rollup-plugin-peer-deps-external": "^2.2.4",
|
|
48
|
+
"rollup-plugin-typescript2": "^0.36.0",
|
|
49
|
+
"typescript": "^5.6.2"
|
|
50
|
+
},
|
|
51
|
+
"peerDependencies": {
|
|
52
|
+
"chess.js": "^1.0.0-beta.8",
|
|
53
|
+
"react": "^18.3.1",
|
|
54
|
+
"react-chess-core": "^0.1.1",
|
|
55
|
+
"react-chessboard": "^4.7.1"
|
|
56
|
+
},
|
|
57
|
+
"devDependencies": {
|
|
58
|
+
"@chromatic-com/storybook": "^1.9.0",
|
|
59
|
+
"@rollup/plugin-commonjs": "^26.0.1",
|
|
60
|
+
"@rollup/plugin-node-resolve": "^15.2.3",
|
|
61
|
+
"@rollup/plugin-terser": "^0.4.4",
|
|
62
|
+
"@storybook/addon-essentials": "^8.2.9",
|
|
63
|
+
"@storybook/addon-interactions": "^8.2.9",
|
|
64
|
+
"@storybook/addon-links": "^8.2.9",
|
|
65
|
+
"@storybook/addon-onboarding": "^8.2.9",
|
|
66
|
+
"@storybook/blocks": "^8.2.9",
|
|
67
|
+
"@storybook/preset-typescript": "^3.0.0",
|
|
68
|
+
"@storybook/react": "^8.2.9",
|
|
69
|
+
"@storybook/react-vite": "^8.2.9",
|
|
70
|
+
"@storybook/test": "^8.2.9",
|
|
71
|
+
"@types/jest": "^29.5.12",
|
|
72
|
+
"@types/react": "^18.3.12",
|
|
73
|
+
"@types/react-dom": "^18.3.1",
|
|
74
|
+
"chess.js": "^1.0.0-beta.8",
|
|
75
|
+
"jest": "^29.7.0",
|
|
76
|
+
"react": "^18.3.1",
|
|
77
|
+
"react-chess-core": "^0.1.1",
|
|
78
|
+
"react-chessboard": "^4.7.1",
|
|
79
|
+
"storybook": "^8.2.9",
|
|
80
|
+
"ts-jest": "^29.2.4",
|
|
81
|
+
"vite": "^5.4.11",
|
|
82
|
+
"vite-tsconfig-paths": "^5.0.1"
|
|
83
|
+
},
|
|
84
|
+
"optionalDependencies": {
|
|
85
|
+
"stockfish": "^18.0.7"
|
|
86
|
+
}
|
|
87
|
+
}
|