@mirasen/react-chessboard 1.0.2 → 1.1.0
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/README.md +54 -4
- package/dist/Chessboard.d.ts +2 -2
- package/dist/Chessboard.js +25 -3
- package/dist/index.d.ts +2 -2
- package/dist/types.d.ts +3 -1
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -14,9 +14,10 @@ Start with a working chessboard, not a board primitive.
|
|
|
14
14
|
|
|
15
15
|
These examples use the same Mirasen chessboard runtime that powers the React component.
|
|
16
16
|
|
|
17
|
-
- [Play a chess.js game](https://mirasen.io/chessboard/examples/chessjs
|
|
18
|
-
- [
|
|
19
|
-
- [Try the
|
|
17
|
+
- [Play a chess.js game](https://mirasen.io/chessboard/examples/chessjs)
|
|
18
|
+
- [Watch 12 live boards](https://mirasen.io/chessboard/examples/live-games-grid)
|
|
19
|
+
- [Try the promotion flow](https://mirasen.io/chessboard/examples/promotion)
|
|
20
|
+
- [Try the minimal example](https://mirasen.io/chessboard/examples/minimal)
|
|
20
21
|
|
|
21
22
|
## Why this exists
|
|
22
23
|
|
|
@@ -33,6 +34,14 @@ Most React chessboard components give you a board primitive and leave the real c
|
|
|
33
34
|
|
|
34
35
|
React owns lifecycle and props. Mirasen owns board rendering, input, interaction, animation, promotion, and extension behavior.
|
|
35
36
|
|
|
37
|
+
## Real-world migration feedback
|
|
38
|
+
|
|
39
|
+
After initially using `react-chessboard` and implementing click-to-move and move highlighting in application code, [TheUnemployedHobo](https://github.com/TheUnemployedHobo) explained why he migrated to Mirasen:
|
|
40
|
+
|
|
41
|
+
> "But the code ended up getting so messy that I didn't even want to look at it anymore. It was painful to read. That's when I decided I needed a library that handled those things properly out of the box, and that's how I ended up switching to yours."
|
|
42
|
+
|
|
43
|
+
— Author of [multiplayer-chess](https://github.com/TheUnemployedHobo/multiplayer-chess) · [Full discussion](https://github.com/TheUnemployedHobo/multiplayer-chess/issues/1#issuecomment-5356049391)
|
|
44
|
+
|
|
36
45
|
## Installation
|
|
37
46
|
|
|
38
47
|
```bash
|
|
@@ -236,7 +245,8 @@ import type {
|
|
|
236
245
|
MoveOutput,
|
|
237
246
|
MoveRequestInput,
|
|
238
247
|
MovabilityInput,
|
|
239
|
-
PositionInput
|
|
248
|
+
PositionInput,
|
|
249
|
+
SquareString
|
|
240
250
|
} from '@mirasen/react-chessboard';
|
|
241
251
|
|
|
242
252
|
type PositionRequest = {
|
|
@@ -256,6 +266,7 @@ type ChessboardProps = {
|
|
|
256
266
|
movability?: MovabilityInput;
|
|
257
267
|
onUIMove?: (move: MoveOutput) => void;
|
|
258
268
|
autoPromoteToQueen?: boolean;
|
|
269
|
+
checkSquare?: SquareString | null;
|
|
259
270
|
className?: string;
|
|
260
271
|
style?: CSSProperties;
|
|
261
272
|
};
|
|
@@ -285,6 +296,14 @@ Called when the user completes a board move. Use this to update your game/rules
|
|
|
285
296
|
|
|
286
297
|
When `true`, promotion automatically selects a queen. When omitted or `false`, the normal built-in promotion flow is used.
|
|
287
298
|
|
|
299
|
+
### `checkSquare`
|
|
300
|
+
|
|
301
|
+
Highlights the king's square when in check. Pass the king's square string (e.g. `'e1'`) to show a red glow; pass `null` or omit to clear it. The chessboard does not detect check itself — your rules layer (e.g. `chess.js`) is responsible for determining when and which square to highlight.
|
|
302
|
+
|
|
303
|
+
```tsx
|
|
304
|
+
<Chessboard checkSquare={chess.isCheck() ? kingSquare : null} ... />
|
|
305
|
+
```
|
|
306
|
+
|
|
288
307
|
### `className` and `style`
|
|
289
308
|
|
|
290
309
|
Applied to the outer container only. They are for layout, not board theming.
|
|
@@ -312,6 +331,36 @@ This keeps the integration boundary explicit:
|
|
|
312
331
|
- The React component displays and collects user moves.
|
|
313
332
|
- Mirasen handles board interaction, target feedback, promotion UI, special-move board updates, and animation.
|
|
314
333
|
|
|
334
|
+
## Board handle (ref)
|
|
335
|
+
|
|
336
|
+
`Chessboard` forwards a `ChessboardHandle` via `ref`. The handle is the full public surface of the underlying `@mirasen/chessboard` board instance — all extensions, all runtime methods, typed directly from the core package.
|
|
337
|
+
|
|
338
|
+
```tsx
|
|
339
|
+
import { Chessboard, type ChessboardHandle } from '@mirasen/react-chessboard';
|
|
340
|
+
import { useEffect, useRef } from 'react';
|
|
341
|
+
|
|
342
|
+
const boardRef = useRef<ChessboardHandle>(null);
|
|
343
|
+
|
|
344
|
+
// once on mount — draw a circle via the annotations extension
|
|
345
|
+
useEffect(() => {
|
|
346
|
+
boardRef.current?.extensions.annotations.circle('e4', { color: 'green' });
|
|
347
|
+
}, []);
|
|
348
|
+
|
|
349
|
+
<Chessboard ref={boardRef} position={...} />
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
The ref gives access to everything the core board exposes: `extensions.*`, `move(...)`, `setPosition(...)`, `setOrientation(...)`, `select(...)`, `getSnapshot()`, and more. When the core package adds a new extension, it is immediately accessible via `ref.current.extensions.<id>` — no wrapper update needed.
|
|
353
|
+
|
|
354
|
+
**When to use ref vs props**
|
|
355
|
+
|
|
356
|
+
Convenience props (`autoPromoteToQueen`, `checkSquare`, `onUIMove`) cover the most common declarative settings. Use the ref when:
|
|
357
|
+
|
|
358
|
+
- you need an extension that has no convenience prop (e.g. `annotations`, `renderer` config)
|
|
359
|
+
- you need to call an imperative method (`annotations.arrow(...)`, `select(...)`)
|
|
360
|
+
- you want to read board state (`getSnapshot()`, `extensions.annotations.getCircles()`)
|
|
361
|
+
|
|
362
|
+
**One channel per setting.** If a convenience prop already covers a setting, do not also write to the same extension property via ref in the same component — they write to the same underlying state and the last write wins.
|
|
363
|
+
|
|
315
364
|
## What you get out of the box
|
|
316
365
|
|
|
317
366
|
The underlying Mirasen board provides the default first-party chessboard baseline:
|
|
@@ -322,6 +371,7 @@ The underlying Mirasen board provides the default first-party chessboard baselin
|
|
|
322
371
|
- active-target feedback
|
|
323
372
|
- legal move hints
|
|
324
373
|
- last-move feedback
|
|
374
|
+
- check square highlight
|
|
325
375
|
- promotion UI
|
|
326
376
|
- optional auto-promotion
|
|
327
377
|
- animation for board-state changes
|
package/dist/Chessboard.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type { ChessboardProps } from './types.js';
|
|
2
|
-
export declare
|
|
1
|
+
import type { ChessboardHandle, ChessboardProps } from './types.js';
|
|
2
|
+
export declare const Chessboard: import("react").ForwardRefExoticComponent<ChessboardProps & import("react").RefAttributes<ChessboardHandle>>;
|
package/dist/Chessboard.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { createBoard } from '@mirasen/chessboard';
|
|
3
|
-
import { useEffect, useRef } from 'react';
|
|
4
|
-
export function Chessboard({ position, externalMove, orientation, movability, onUIMove, autoPromoteToQueen, className, style }) {
|
|
3
|
+
import { forwardRef, useEffect, useRef } from 'react';
|
|
4
|
+
export const Chessboard = forwardRef(function Chessboard({ position, externalMove, orientation, movability, onUIMove, autoPromoteToQueen, checkSquare, className, style }, ref) {
|
|
5
5
|
const containerRef = useRef(null);
|
|
6
6
|
const boardRef = useRef(null);
|
|
7
7
|
const onUIMoveRef = useRef(onUIMove);
|
|
@@ -24,6 +24,22 @@ export function Chessboard({ position, externalMove, orientation, movability, on
|
|
|
24
24
|
boardRef.current = null;
|
|
25
25
|
};
|
|
26
26
|
}, []);
|
|
27
|
+
// Forward external ref to the same board instance
|
|
28
|
+
useEffect(() => {
|
|
29
|
+
const board = boardRef.current;
|
|
30
|
+
if (!board)
|
|
31
|
+
return;
|
|
32
|
+
if (typeof ref === 'function') {
|
|
33
|
+
ref(board);
|
|
34
|
+
return () => ref(null);
|
|
35
|
+
}
|
|
36
|
+
if (ref) {
|
|
37
|
+
ref.current = board;
|
|
38
|
+
return () => {
|
|
39
|
+
ref.current = null;
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
}, [ref]);
|
|
27
43
|
// Position sync
|
|
28
44
|
useEffect(() => {
|
|
29
45
|
if (!boardRef.current)
|
|
@@ -66,5 +82,11 @@ export function Chessboard({ position, externalMove, orientation, movability, on
|
|
|
66
82
|
return;
|
|
67
83
|
boardRef.current.extensions.autoPromote.toQueen = autoPromoteToQueen ?? false;
|
|
68
84
|
}, [autoPromoteToQueen]);
|
|
85
|
+
// checkSquare sync
|
|
86
|
+
useEffect(() => {
|
|
87
|
+
if (!boardRef.current)
|
|
88
|
+
return;
|
|
89
|
+
boardRef.current.extensions.check.square = checkSquare ?? null;
|
|
90
|
+
}, [checkSquare]);
|
|
69
91
|
return _jsx("div", { ref: containerRef, className: className, style: style });
|
|
70
|
-
}
|
|
92
|
+
});
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export { Chessboard } from './Chessboard.js';
|
|
2
|
-
export type { BoardOrientation, ChessboardProps, ExternalMoveRequest, PositionRequest } from './types.js';
|
|
3
|
-
export type { ColorInput, MovabilityInput, MoveOutput, MoveRequestInput, PositionInput } from '@mirasen/chessboard';
|
|
2
|
+
export type { BoardOrientation, ChessboardHandle, ChessboardProps, ExternalMoveRequest, PositionRequest } from './types.js';
|
|
3
|
+
export type { ColorInput, MovabilityInput, MoveOutput, MoveRequestInput, PositionInput, SquareString } from '@mirasen/chessboard';
|
package/dist/types.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import type { ColorInput, MovabilityInput, MoveOutput, MoveRequestInput, PositionInput } from '@mirasen/chessboard';
|
|
1
|
+
import type { Chessboard as CoreChessboard, ColorInput, MovabilityInput, MoveOutput, MoveRequestInput, PositionInput, SquareString } from '@mirasen/chessboard';
|
|
2
2
|
import type { CSSProperties } from 'react';
|
|
3
|
+
export type ChessboardHandle = CoreChessboard;
|
|
3
4
|
export type BoardOrientation = ColorInput;
|
|
4
5
|
export type PositionRequest = {
|
|
5
6
|
id: string | number;
|
|
@@ -16,6 +17,7 @@ export type ChessboardProps = {
|
|
|
16
17
|
movability?: MovabilityInput;
|
|
17
18
|
onUIMove?: (move: MoveOutput) => void;
|
|
18
19
|
autoPromoteToQueen?: boolean;
|
|
20
|
+
checkSquare?: SquareString | null;
|
|
19
21
|
className?: string;
|
|
20
22
|
style?: CSSProperties;
|
|
21
23
|
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mirasen/react-chessboard",
|
|
3
3
|
"description": "A React chessboard component with built-in interaction, promotion, animation, and chess.js integration.",
|
|
4
|
-
"version": "1.0
|
|
4
|
+
"version": "1.1.0",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"mirasen",
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"LICENSE"
|
|
57
57
|
],
|
|
58
58
|
"dependencies": {
|
|
59
|
-
"@mirasen/chessboard": "^1.
|
|
59
|
+
"@mirasen/chessboard": "^1.4.0"
|
|
60
60
|
},
|
|
61
61
|
"peerDependencies": {
|
|
62
62
|
"react": ">=18",
|
|
@@ -69,18 +69,18 @@
|
|
|
69
69
|
}
|
|
70
70
|
},
|
|
71
71
|
"devDependencies": {
|
|
72
|
-
"@changesets/cli": "^
|
|
72
|
+
"@changesets/cli": "^3.0.0",
|
|
73
73
|
"@eslint/compat": "^2.0.0",
|
|
74
74
|
"@eslint/js": "^10.0.1",
|
|
75
75
|
"@testing-library/react": "^16.3.2",
|
|
76
76
|
"@types/node": "^26.0.0",
|
|
77
77
|
"@types/react": "^18.3.0",
|
|
78
78
|
"@types/react-dom": "^18.3.0",
|
|
79
|
-
"@vitest/coverage-
|
|
79
|
+
"@vitest/coverage-v8": "^4.0.3",
|
|
80
80
|
"eslint": "^10.0.2",
|
|
81
81
|
"eslint-config-prettier": "^10.1.2",
|
|
82
82
|
"globals": "^17.4.0",
|
|
83
|
-
"jsdom": "^
|
|
83
|
+
"jsdom": "^30.0.0",
|
|
84
84
|
"prettier": "^3.5.3",
|
|
85
85
|
"publint": "^0.3.11",
|
|
86
86
|
"react": "^18.3.1",
|