@react-chess-tools/react-chess-puzzle 1.0.0 → 1.0.1

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/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # @react-chess-tools/react-chess-puzzle
2
2
 
3
+ ## 1.0.1
4
+
5
+ ### Patch Changes
6
+
7
+ - f9b7665: feat: add ref forwarding, HTML attributes, and improved asChild pattern
8
+ - Updated dependencies [f9b7665]
9
+ - @react-chess-tools/react-chess-game@1.0.1
10
+
3
11
  ## 1.0.0
4
12
 
5
13
  ### Major Changes
package/README.md ADDED
@@ -0,0 +1,568 @@
1
+ <div align="center">
2
+ <h1>@react-chess-tools/react-chess-puzzle</h1>
3
+ <p>A lightweight, customizable React component library for rendering and interacting with chess puzzles</p>
4
+
5
+ [![npm version](https://img.shields.io/npm/v/@react-chess-tools/react-chess-puzzle.svg)](https://www.npmjs.com/package/@react-chess-tools/react-chess-puzzle)
6
+ [![npm downloads](https://img.shields.io/npm/dm/@react-chess-tools/react-chess-puzzle.svg)](https://www.npmjs.com/package/@react-chess-tools/react-chess-puzzle)
7
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
8
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.x-blue.svg)](https://www.typescriptlang.org/)
9
+
10
+ </div>
11
+
12
+ ## Table of Contents
13
+
14
+ - [Overview](#overview)
15
+ - [Features](#features)
16
+ - [Installation](#installation)
17
+ - [Quick Start](#quick-start)
18
+ - [Demo](#demo)
19
+ - [Puzzle Solving Flow](#puzzle-solving-flow)
20
+ - [API Reference](#api-reference)
21
+ - [ChessPuzzle.Root](#chesspuzzleroot)
22
+ - [ChessPuzzle.Board](#chesspuzzleboard)
23
+ - [ChessPuzzle.Reset](#chesspuzzlereset)
24
+ - [ChessPuzzle.Hint](#chesspuzzlehint)
25
+ - [Hooks](#hooks)
26
+ - [useChessPuzzleContext](#usechesspuzzlecontext)
27
+ - [useChessGameContext](#usechessgamecontext)
28
+ - [Integration with react-chess-game](#integration-with-react-chess-game)
29
+ - [Examples](#examples)
30
+ - [License](#license)
31
+
32
+ ## Overview
33
+
34
+ `@react-chess-tools/react-chess-puzzle` is a React component library for creating interactive chess puzzle experiences. Built on top of [@react-chess-tools/react-chess-game](https://www.npmjs.com/package/@react-chess-tools/react-chess-game), it provides puzzle-specific features like move validation, hints, and progress tracking.
35
+
36
+ ## Features
37
+
38
+ - **Move Validation** - Automatically validates moves against the puzzle solution
39
+ - **Hints** - Show the next correct move to help users
40
+ - **Progress Tracking** - Track puzzle state (not-started, in-progress, solved, failed)
41
+ - **Callbacks** - React to puzzle solve/fail events
42
+ - **Built-in Reset** - Easily restart puzzles or load new ones
43
+ - **Sound Effects** - Integrates with ChessGame.Sounds for audio feedback
44
+ - **Keyboard Controls** - Navigate through puzzle moves with keyboard
45
+ - **TypeScript** - Full TypeScript support with comprehensive type definitions
46
+
47
+ ## Installation
48
+
49
+ ```bash
50
+ npm install @react-chess-tools/react-chess-puzzle
51
+ ```
52
+
53
+ ```bash
54
+ yarn add @react-chess-tools/react-chess-puzzle
55
+ ```
56
+
57
+ ```bash
58
+ pnpm add @react-chess-tools/react-chess-puzzle
59
+ ```
60
+
61
+ ## Quick Start
62
+
63
+ ```tsx
64
+ import { ChessPuzzle } from "@react-chess-tools/react-chess-puzzle";
65
+
66
+ function App() {
67
+ const puzzle = {
68
+ fen: "r1bqkbnr/pppp1ppp/2n5/4p3/4P3/5N2/PPPP1PPP/RNBQKB1R w KQkq - 2 3",
69
+ moves: ["d2d4", "e5d4", "f3d4"],
70
+ makeFirstMove: false,
71
+ };
72
+
73
+ return (
74
+ <ChessPuzzle.Root puzzle={puzzle}>
75
+ <ChessPuzzle.Board />
76
+ <ChessPuzzle.Reset>Restart</ChessPuzzle.Reset>
77
+ <ChessPuzzle.Hint>Get Hint</ChessPuzzle.Hint>
78
+ </ChessPuzzle.Root>
79
+ );
80
+ }
81
+ ```
82
+
83
+ ## Demo
84
+
85
+ Visit the [live demo](https://react-chess-tools.vercel.app/) to see the component in action.
86
+
87
+ ## Puzzle Solving Flow
88
+
89
+ 1. **Initial Setup** - The board displays the position from the FEN string
90
+ 2. **First Move** - If `makeFirstMove` is `true`, the component automatically plays the first move
91
+ 3. **User Interaction** - The user attempts to solve the puzzle by making moves
92
+ 4. **Validation** - Each move is validated against the solution:
93
+ - Correct move: The puzzle continues, opponent's response is auto-played
94
+ - Incorrect move: The puzzle is marked as failed
95
+ 5. **Completion** - When all correct moves are made, the puzzle is marked as solved
96
+
97
+ ## API Reference
98
+
99
+ ### ChessPuzzle.Root
100
+
101
+ The root component that provides puzzle context to all child components.
102
+
103
+ **Note:** This is a logic-only component (Context Provider). It does not render any DOM elements.
104
+
105
+ #### Props
106
+
107
+ | Name | Type | Default | Description |
108
+ | ---------- | --------------------------------------- | ------- | --------------------------------------- |
109
+ | `puzzle` | `Puzzle` | - | The puzzle configuration (required) |
110
+ | `onSolve` | `(ctx: ChessPuzzleContextType) => void` | - | Callback when puzzle is solved |
111
+ | `onFail` | `(ctx: ChessPuzzleContextType) => void` | - | Callback when an incorrect move is made |
112
+ | `theme` | `PartialChessPuzzleTheme` | - | Optional theme configuration |
113
+ | `children` | `ReactNode` | - | Child components |
114
+
115
+ #### Puzzle Object
116
+
117
+ | Property | Type | Default | Description |
118
+ | --------------- | ---------- | ------- | ------------------------------------------- |
119
+ | `fen` | `string` | - | Initial position in FEN notation |
120
+ | `moves` | `string[]` | - | Solution moves in algebraic or UCI notation |
121
+ | `makeFirstMove` | `boolean` | `false` | Whether to auto-play the first move |
122
+
123
+ #### Example
124
+
125
+ ```tsx
126
+ <ChessPuzzle.Root
127
+ puzzle={{
128
+ fen: "4kb1r/p2r1ppp/4qn2/1B2p1B1/4P3/1Q6/PPP2PPP/2KR4 w k - 0 1",
129
+ moves: ["Bxd7+", "Nxd7", "Qb8+", "Nxb8", "Rd8#"],
130
+ makeFirstMove: false,
131
+ }}
132
+ onSolve={(ctx) => console.log("Solved!", ctx.movesPlayed)}
133
+ onFail={(ctx) => console.log("Failed at move", ctx.movesPlayed)}
134
+ >
135
+ <ChessPuzzle.Board />
136
+ </ChessPuzzle.Root>
137
+ ```
138
+
139
+ ### ChessPuzzle.Board
140
+
141
+ Renders the chess board. Delegates to `ChessGame.Board` under the hood.
142
+
143
+ Supports **ref forwarding** and all standard **HTML div attributes** (className, style, id, data-_, aria-_, etc.).
144
+
145
+ #### Props
146
+
147
+ | Name | Type | Description |
148
+ | ----------- | -------------------------------- | --------------------------------------------- |
149
+ | `options` | `ChessboardOptions` | Options forwarded to `react-chessboard` v5 |
150
+ | `ref` | `Ref<HTMLDivElement>` | Forwarded ref to the underlying board element |
151
+ | `className` | `string` | Custom CSS class names |
152
+ | `style` | `CSSProperties` | Custom inline styles |
153
+ | `...` | `HTMLAttributes<HTMLDivElement>` | All standard HTML div attributes |
154
+
155
+ #### Example
156
+
157
+ ```tsx
158
+ <ChessPuzzle.Root puzzle={puzzle}>
159
+ <ChessPuzzle.Board
160
+ options={{
161
+ showNotation: true,
162
+ animationDurationInMs: 200,
163
+ }}
164
+ className="puzzle-board"
165
+ style={{ boxShadow: "0 4px 6px rgba(0,0,0,0.1)" }}
166
+ />
167
+ </ChessPuzzle.Root>
168
+ ```
169
+
170
+ ### ChessPuzzle.Reset
171
+
172
+ A button component that resets the current puzzle or loads a new one.
173
+
174
+ Supports **ref forwarding**, **asChild pattern**, and all standard **HTML button attributes** (className, style, disabled, etc.).
175
+
176
+ #### Props
177
+
178
+ | Name | Type | Default | Description |
179
+ | ----------- | ----------------------------------------- | ----------------------------------- | --------------------------------------------------- |
180
+ | `puzzle` | `Puzzle` | - | New puzzle to load (resets current if not provided) |
181
+ | `onReset` | `(ctx: ChessPuzzleContextType) => void` | - | Callback after reset |
182
+ | `showOn` | `Status[]` | `["failed", "solved"]` | States in which the button is visible |
183
+ | `asChild` | `boolean` | `false` | Render as child element (slot pattern) |
184
+ | `ref` | `Ref<HTMLButtonElement>` | Forwarded ref to the button element |
185
+ | `className` | `string` | Custom CSS class names |
186
+ | `...` | `ButtonHTMLAttributes<HTMLButtonElement>` | All standard HTML button attributes |
187
+
188
+ **Status values:** `"not-started"`, `"in-progress"`, `"solved"`, `"failed"`
189
+
190
+ #### Example
191
+
192
+ ```tsx
193
+ <ChessPuzzle.Root puzzle={puzzle}>
194
+ <ChessPuzzle.Board />
195
+ <ChessPuzzle.Reset>Try Again</ChessPuzzle.Reset>
196
+ <ChessPuzzle.Reset puzzle={nextPuzzle}>Next Puzzle</ChessPuzzle.Reset>
197
+ </ChessPuzzle.Root>
198
+ ```
199
+
200
+ #### Using asChild Pattern
201
+
202
+ ```tsx
203
+ // Render as a custom button component
204
+ import { MyCustomButton } from './MyButton';
205
+
206
+ <ChessPuzzle.Root puzzle={puzzle}>
207
+ <ChessPuzzle.Board />
208
+ <ChessPuzzle.Reset asChild>
209
+ <MyCustomButton variant="primary">Try Again</MyCustomButton>
210
+ </ChessPuzzle.Reset>
211
+ </ChessPuzzle.Root>
212
+
213
+ // Render as a link
214
+ <ChessPuzzle.Root puzzle={puzzle}>
215
+ <ChessPuzzle.Board />
216
+ <ChessPuzzle.Reset asChild>
217
+ <a href="#" onClick={(e) => e.preventDefault()}>
218
+ Restart Puzzle
219
+ </a>
220
+ </ChessPuzzle.Reset>
221
+ </ChessPuzzle.Root>
222
+ ```
223
+
224
+ #### Event Handler Composition
225
+
226
+ When using `asChild`, both your component's onClick and the Reset's onClick handler will work together:
227
+
228
+ ```tsx
229
+ <ChessPuzzle.Reset asChild>
230
+ <button onClick={() => console.log("Custom handler")} className="custom-btn">
231
+ Try Again
232
+ </button>
233
+ </ChessPuzzle.Reset>
234
+ // Both custom handler and reset logic will execute
235
+ ```
236
+
237
+ ### ChessPuzzle.Hint
238
+
239
+ A button that highlights the next correct move on the board.
240
+
241
+ Supports **ref forwarding**, **asChild pattern**, and all standard **HTML button attributes** (className, style, disabled, etc.).
242
+
243
+ #### Props
244
+
245
+ | Name | Type | Default | Description |
246
+ | ----------- | ----------------------------------------- | ----------------------------------- | -------------------------------------- |
247
+ | `showOn` | `Status[]` | `["not-started", "in-progress"]` | States in which the button is visible |
248
+ | `asChild` | `boolean` | `false` | Render as child element (slot pattern) |
249
+ | `ref` | `Ref<HTMLButtonElement>` | Forwarded ref to the button element |
250
+ | `className` | `string` | Custom CSS class names |
251
+ | `...` | `ButtonHTMLAttributes<HTMLButtonElement>` | All standard HTML button attributes |
252
+
253
+ #### Example
254
+
255
+ ```tsx
256
+ const puzzle = {
257
+ fen: "r1bqkbnr/pppp1ppp/2n5/4p3/4P3/5N2/PPPP1PPP/RNBQKB1R w KQkq - 2 3",
258
+ moves: ["d2d4", "e5d4", "f3d4"],
259
+ makeFirstMove: false,
260
+ };
261
+
262
+ <ChessPuzzle.Root puzzle={puzzle}>
263
+ <ChessPuzzle.Board />
264
+ <ChessPuzzle.Hint>Show Hint</ChessPuzzle.Hint>
265
+ </ChessPuzzle.Root>;
266
+ ```
267
+
268
+ #### Using asChild Pattern
269
+
270
+ ```tsx
271
+ <ChessPuzzle.Root puzzle={puzzle}>
272
+ <ChessPuzzle.Board />
273
+ <ChessPuzzle.Hint asChild>
274
+ <button className="hint-btn">💡 Show Hint</button>
275
+ </ChessPuzzle.Hint>
276
+ </ChessPuzzle.Root>
277
+ ```
278
+
279
+ ## Hooks
280
+
281
+ ### useChessPuzzleContext
282
+
283
+ Access the puzzle state and methods from any child component.
284
+
285
+ ```tsx
286
+ import { useChessPuzzleContext } from "@react-chess-tools/react-chess-puzzle";
287
+
288
+ function PuzzleStatus() {
289
+ const { puzzleState, movesPlayed, totalMoves, resetPuzzle, onHint } =
290
+ useChessPuzzleContext();
291
+
292
+ return (
293
+ <div>
294
+ <p>Status: {puzzleState}</p>
295
+ <p>
296
+ Progress: {movesPlayed}/{totalMoves} moves
297
+ </p>
298
+ <button onClick={resetPuzzle}>Reset</button>
299
+ <button onClick={onHint}>Hint</button>
300
+ </div>
301
+ );
302
+ }
303
+ ```
304
+
305
+ #### Return Values
306
+
307
+ | Property | Type | Description |
308
+ | -------------- | -------------------------- | -------------------------------------- |
309
+ | `status` | `Status` | Current puzzle state |
310
+ | `puzzleState` | `Status` | Alias for `status` |
311
+ | `movesPlayed` | `number` | Number of correct moves made |
312
+ | `totalMoves` | `number` | Total moves in the solution |
313
+ | `puzzle` | `Puzzle` | The current puzzle object |
314
+ | `hint` | `Hint` | Current hint state |
315
+ | `nextMove` | `string \| null` | The next correct move |
316
+ | `isPlayerTurn` | `boolean` | Whether it's the player's turn to move |
317
+ | `changePuzzle` | `(puzzle: Puzzle) => void` | Load a new puzzle |
318
+ | `resetPuzzle` | `() => void` | Reset the current puzzle |
319
+ | `onHint` | `() => void` | Show hint for next move |
320
+
321
+ ### useChessGameContext
322
+
323
+ Since `react-chess-puzzle` is built on `react-chess-game`, you can also access the underlying game context.
324
+
325
+ ```tsx
326
+ import { useChessGameContext } from "@react-chess-tools/react-chess-game";
327
+
328
+ function BoardInfo() {
329
+ const { currentFen, info, methods } = useChessGameContext();
330
+
331
+ return (
332
+ <div>
333
+ <p>Turn: {info.turn === "w" ? "White" : "Black"}</p>
334
+ <button onClick={() => methods.flipBoard()}>Flip Board</button>
335
+ </div>
336
+ );
337
+ }
338
+ ```
339
+
340
+ ## Integration with react-chess-game
341
+
342
+ Since `react-chess-puzzle` is built on `react-chess-game`, you can use any of its components:
343
+
344
+ ### Adding Sound Effects
345
+
346
+ ```tsx
347
+ import { ChessPuzzle } from "@react-chess-tools/react-chess-puzzle";
348
+ import { ChessGame } from "@react-chess-tools/react-chess-game";
349
+
350
+ function PuzzleWithSounds() {
351
+ const puzzle = {
352
+ fen: "r1bqkbnr/pppp1ppp/2n5/4p3/4P3/5N2/PPPP1PPP/RNBQKB1R w KQkq - 2 3",
353
+ moves: ["d2d4", "e5d4", "f3d4"],
354
+ };
355
+
356
+ return (
357
+ <ChessPuzzle.Root puzzle={puzzle}>
358
+ <ChessGame.Sounds />
359
+ <ChessPuzzle.Board />
360
+ </ChessPuzzle.Root>
361
+ );
362
+ }
363
+ ```
364
+
365
+ ### Adding Keyboard Controls
366
+
367
+ ```tsx
368
+ import { ChessPuzzle } from "@react-chess-tools/react-chess-puzzle";
369
+ import { ChessGame } from "@react-chess-tools/react-chess-game";
370
+
371
+ function PuzzleWithKeyboard() {
372
+ const puzzle = {
373
+ fen: "r1bqkbnr/pppp1ppp/2n5/4p3/4P3/5N2/PPPP1PPP/RNBQKB1R w KQkq - 2 3",
374
+ moves: ["d2d4", "e5d4", "f3d4"],
375
+ };
376
+
377
+ return (
378
+ <ChessPuzzle.Root puzzle={puzzle}>
379
+ <ChessGame.KeyboardControls />
380
+ <ChessPuzzle.Board />
381
+ </ChessPuzzle.Root>
382
+ );
383
+ }
384
+ ```
385
+
386
+ ## Examples
387
+
388
+ ### Basic Puzzle
389
+
390
+ ```tsx
391
+ import { ChessPuzzle } from "@react-chess-tools/react-chess-puzzle";
392
+
393
+ function BasicPuzzle() {
394
+ const puzzle = {
395
+ fen: "r1bqkbnr/pppp1ppp/2n5/4p3/4P3/5N2/PPPP1PPP/RNBQKB1R w KQkq - 2 3",
396
+ moves: ["d2d4", "e5d4", "f3d4"],
397
+ makeFirstMove: false,
398
+ };
399
+
400
+ return (
401
+ <ChessPuzzle.Root puzzle={puzzle}>
402
+ <ChessPuzzle.Board />
403
+ <ChessPuzzle.Reset>Restart</ChessPuzzle.Reset>
404
+ <ChessPuzzle.Hint>Hint</ChessPuzzle.Hint>
405
+ </ChessPuzzle.Root>
406
+ );
407
+ }
408
+ ```
409
+
410
+ ### Puzzle with Callbacks
411
+
412
+ ```tsx
413
+ import {
414
+ ChessPuzzle,
415
+ type ChessPuzzleContextType,
416
+ } from "@react-chess-tools/react-chess-puzzle";
417
+ import { useState } from "react";
418
+
419
+ function PuzzleWithScore() {
420
+ const [score, setScore] = useState(0);
421
+
422
+ const handleSolve = (ctx: ChessPuzzleContextType) => {
423
+ setScore((prev) => prev + 10);
424
+ console.log(`Solved in ${ctx.movesPlayed} moves!`);
425
+ };
426
+
427
+ const handleFail = (ctx: ChessPuzzleContextType) => {
428
+ setScore((prev) => Math.max(0, prev - 5));
429
+ console.log("Incorrect move!");
430
+ };
431
+
432
+ return (
433
+ <div>
434
+ <p>Score: {score}</p>
435
+ <ChessPuzzle.Root
436
+ puzzle={puzzle}
437
+ onSolve={handleSolve}
438
+ onFail={handleFail}
439
+ >
440
+ <ChessPuzzle.Board />
441
+ <ChessPuzzle.Reset>Try Again</ChessPuzzle.Reset>
442
+ </ChessPuzzle.Root>
443
+ </div>
444
+ );
445
+ }
446
+ ```
447
+
448
+ ### Puzzle Trainer with Multiple Puzzles
449
+
450
+ ```tsx
451
+ import {
452
+ ChessPuzzle,
453
+ type ChessPuzzleContextType,
454
+ } from "@react-chess-tools/react-chess-puzzle";
455
+ import { ChessGame } from "@react-chess-tools/react-chess-game";
456
+ import { useState } from "react";
457
+
458
+ const puzzles = [
459
+ {
460
+ fen: "4kb1r/p2r1ppp/4qn2/1B2p1B1/4P3/1Q6/PPP2PPP/2KR4 w k - 0 1",
461
+ moves: ["Bxd7+", "Nxd7", "Qb8+", "Nxb8", "Rd8#"],
462
+ makeFirstMove: false,
463
+ },
464
+ {
465
+ fen: "6k1/5p1p/p1q1p1p1/1pB1P3/1Pr3Pn/P4P1P/4Q3/3R2K1 b - - 0 31",
466
+ moves: ["h4f3", "e2f3", "c4c5", "d1d8", "g8g7", "f3f6"],
467
+ makeFirstMove: true,
468
+ },
469
+ ];
470
+
471
+ function PuzzleTrainer() {
472
+ const [currentIndex, setCurrentIndex] = useState(0);
473
+ const [score, setScore] = useState(0);
474
+
475
+ const nextPuzzle = () => {
476
+ setCurrentIndex((prev) => (prev + 1) % puzzles.length);
477
+ };
478
+
479
+ const handleSolve = (ctx: ChessPuzzleContextType) => {
480
+ setScore((prev) => prev + 10);
481
+ nextPuzzle();
482
+ };
483
+
484
+ const handleFail = () => {
485
+ setScore((prev) => Math.max(0, prev - 5));
486
+ nextPuzzle();
487
+ };
488
+
489
+ return (
490
+ <div className="puzzle-trainer">
491
+ <div className="score">Score: {score}</div>
492
+
493
+ <ChessPuzzle.Root
494
+ puzzle={puzzles[currentIndex]}
495
+ onSolve={handleSolve}
496
+ onFail={handleFail}
497
+ >
498
+ <ChessGame.Sounds />
499
+ <ChessGame.KeyboardControls />
500
+
501
+ <ChessPuzzle.Board />
502
+
503
+ <div className="controls">
504
+ <ChessPuzzle.Reset>Restart</ChessPuzzle.Reset>
505
+ <ChessPuzzle.Hint>Hint</ChessPuzzle.Hint>
506
+ <ChessPuzzle.Reset
507
+ puzzle={puzzles[(currentIndex + 1) % puzzles.length]}
508
+ >
509
+ Skip
510
+ </ChessPuzzle.Reset>
511
+ </div>
512
+ </ChessPuzzle.Root>
513
+ </div>
514
+ );
515
+ }
516
+ ```
517
+
518
+ ### Custom Status Display
519
+
520
+ ```tsx
521
+ import {
522
+ ChessPuzzle,
523
+ useChessPuzzleContext,
524
+ } from "@react-chess-tools/react-chess-puzzle";
525
+
526
+ function PuzzleStatusDisplay() {
527
+ const { puzzleState, movesPlayed, totalMoves } = useChessPuzzleContext();
528
+
529
+ const messages = {
530
+ "not-started": "Make your move to start",
531
+ "in-progress": `Progress: ${movesPlayed}/${totalMoves} moves`,
532
+ solved: "Puzzle solved! Well done!",
533
+ failed: "Incorrect move. Try again!",
534
+ };
535
+
536
+ return <div className={`status ${puzzleState}`}>{messages[puzzleState]}</div>;
537
+ }
538
+
539
+ function ResetLabel() {
540
+ const { puzzleState } = useChessPuzzleContext();
541
+ return puzzleState === "solved" ? "Next Puzzle" : "Try Again";
542
+ }
543
+
544
+ function PuzzleWithStatus() {
545
+ const puzzle = {
546
+ fen: "r1bqkbnr/pppp1ppp/2n5/4p3/4P3/5N2/PPPP1PPP/RNBQKB1R w KQkq - 2 3",
547
+ moves: ["d2d4", "e5d4", "f3d4"],
548
+ };
549
+
550
+ return (
551
+ <ChessPuzzle.Root puzzle={puzzle}>
552
+ <PuzzleStatusDisplay />
553
+ <ChessPuzzle.Board />
554
+ <ChessPuzzle.Reset showOn={["solved", "failed"]}>
555
+ <ResetLabel />
556
+ </ChessPuzzle.Reset>
557
+ </ChessPuzzle.Root>
558
+ );
559
+ }
560
+ ```
561
+
562
+ ## License
563
+
564
+ This project is [MIT](https://opensource.org/licenses/MIT) licensed.
565
+
566
+ ## Show Your Support
567
+
568
+ Give a star if this project helped you!