react-native-chess-kit 0.5.2 → 0.5.4
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 +19 -0
- package/lib/commonjs/board-arrows.js +7 -7
- package/lib/commonjs/board-coordinates.js +8 -8
- package/lib/commonjs/board.js +48 -39
- package/lib/commonjs/board.js.map +1 -1
- package/lib/commonjs/promotion-picker.js +9 -9
- package/lib/commonjs/promotion-picker.js.map +1 -1
- package/lib/commonjs/static-board.js +7 -7
- package/lib/commonjs/static-board.js.map +1 -1
- package/lib/commonjs/use-board-gesture.js +26 -26
- package/lib/commonjs/use-board-gesture.js.map +1 -1
- package/lib/commonjs/use-board-state.js +13 -4
- package/lib/commonjs/use-board-state.js.map +1 -1
- package/lib/module/board-arrows.js +7 -7
- package/lib/module/board-coordinates.js +8 -8
- package/lib/module/board.js +48 -39
- package/lib/module/board.js.map +1 -1
- package/lib/module/promotion-picker.js +9 -9
- package/lib/module/promotion-picker.js.map +1 -1
- package/lib/module/static-board.js +7 -7
- package/lib/module/static-board.js.map +1 -1
- package/lib/module/use-board-gesture.js +26 -26
- package/lib/module/use-board-gesture.js.map +1 -1
- package/lib/module/use-board-state.js +13 -4
- package/lib/module/use-board-state.js.map +1 -1
- package/lib/typescript/board-coordinates.d.ts.map +1 -1
- package/lib/typescript/board.d.ts.map +1 -1
- package/lib/typescript/promotion-picker.d.ts.map +1 -1
- package/lib/typescript/static-board.d.ts.map +1 -1
- package/lib/typescript/types.d.ts +14 -3
- package/lib/typescript/types.d.ts.map +1 -1
- package/lib/typescript/use-board-gesture.d.ts.map +1 -1
- package/lib/typescript/use-board-state.d.ts.map +1 -1
- package/package.json +95 -75
- package/src/board-arrows.tsx +197 -197
- package/src/board-coordinates.tsx +192 -192
- package/src/board.tsx +59 -56
- package/src/promotion-picker.tsx +147 -147
- package/src/static-board.tsx +186 -187
- package/src/types.ts +27 -6
- package/src/use-board-gesture.ts +459 -429
- package/src/use-board-state.ts +23 -14
package/src/static-board.tsx
CHANGED
|
@@ -1,187 +1,186 @@
|
|
|
1
|
-
import React, { useState, useCallback, useMemo } from 'react';
|
|
2
|
-
import { View, type LayoutChangeEvent } from 'react-native';
|
|
3
|
-
|
|
4
|
-
import type { StaticBoardProps,
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
*
|
|
20
|
-
*
|
|
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
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
const
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
// ---
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
{
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
{
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
});
|
|
1
|
+
import React, { useState, useCallback, useMemo } from 'react';
|
|
2
|
+
import { View, type LayoutChangeEvent } from 'react-native';
|
|
3
|
+
|
|
4
|
+
import type { StaticBoardProps, PieceCode } from './types';
|
|
5
|
+
import {
|
|
6
|
+
DEFAULT_BOARD_COLORS,
|
|
7
|
+
DEFAULT_LAST_MOVE_COLOR,
|
|
8
|
+
COORDINATE_GUTTER_SCALE,
|
|
9
|
+
} from './constants';
|
|
10
|
+
import { DefaultPieceSet } from './pieces';
|
|
11
|
+
import { useBoardPieces, squareToXY } from './use-board-pieces';
|
|
12
|
+
import { BoardBackground } from './board-background';
|
|
13
|
+
import { BoardCoordinates } from './board-coordinates';
|
|
14
|
+
import { BoardHighlights } from './board-highlights';
|
|
15
|
+
import { BoardArrows } from './board-arrows';
|
|
16
|
+
import { BoardAnnotations } from './board-annotations';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Non-interactive chess board — optimized for lists, thumbnails, and analysis previews.
|
|
20
|
+
*
|
|
21
|
+
* No gesture handler, no drag ghost, no legal move dots.
|
|
22
|
+
* Just: background + coordinates + highlights + pieces + arrows + annotations.
|
|
23
|
+
*
|
|
24
|
+
* Significantly lighter than the full Board component.
|
|
25
|
+
*/
|
|
26
|
+
export const StaticBoard = React.memo(function StaticBoard({
|
|
27
|
+
fen,
|
|
28
|
+
orientation = 'white',
|
|
29
|
+
boardSize: boardSizeProp,
|
|
30
|
+
colors,
|
|
31
|
+
coordinatePosition: coordinatePositionProp,
|
|
32
|
+
withCoordinates,
|
|
33
|
+
renderPiece,
|
|
34
|
+
pieceSet,
|
|
35
|
+
lastMove,
|
|
36
|
+
highlights,
|
|
37
|
+
arrows,
|
|
38
|
+
annotations,
|
|
39
|
+
}: StaticBoardProps) {
|
|
40
|
+
// --- Auto-sizing via onLayout when boardSize not provided ---
|
|
41
|
+
const [measuredSize, setMeasuredSize] = useState(0);
|
|
42
|
+
const handleLayout = useCallback((e: LayoutChangeEvent) => {
|
|
43
|
+
const { width, height } = e.nativeEvent.layout;
|
|
44
|
+
setMeasuredSize(Math.min(width, height));
|
|
45
|
+
}, []);
|
|
46
|
+
|
|
47
|
+
const outerSize = boardSizeProp ?? measuredSize;
|
|
48
|
+
const boardColors = colors ?? DEFAULT_BOARD_COLORS;
|
|
49
|
+
|
|
50
|
+
// Resolve coordinate position: new prop > legacy boolean > 'none'
|
|
51
|
+
const coordinatePosition = coordinatePositionProp ?? (withCoordinates ? 'inside' : 'none');
|
|
52
|
+
const isOutside = coordinatePosition === 'outside';
|
|
53
|
+
const isCoordVisible = coordinatePosition !== 'none';
|
|
54
|
+
|
|
55
|
+
const gutterWidth = isOutside ? Math.round((outerSize / 8) * COORDINATE_GUTTER_SCALE) : 0;
|
|
56
|
+
const boardSize = isOutside ? outerSize - gutterWidth : outerSize;
|
|
57
|
+
const squareSize = boardSize / 8;
|
|
58
|
+
|
|
59
|
+
// --- Piece data from FEN ---
|
|
60
|
+
const pieces = useBoardPieces(fen);
|
|
61
|
+
|
|
62
|
+
// --- Resolve piece renderer: renderPiece > pieceSet > DefaultPieceSet ---
|
|
63
|
+
const resolvedRenderer = useMemo(() => {
|
|
64
|
+
if (renderPiece) return renderPiece;
|
|
65
|
+
const set = pieceSet ?? DefaultPieceSet;
|
|
66
|
+
return (code: string, size: number) => {
|
|
67
|
+
const renderer = set[code as PieceCode];
|
|
68
|
+
if (renderer) return renderer(size);
|
|
69
|
+
// Fallback for unknown piece codes
|
|
70
|
+
return <View style={{ width: size, height: size }} />;
|
|
71
|
+
};
|
|
72
|
+
}, [renderPiece, pieceSet]);
|
|
73
|
+
|
|
74
|
+
// If no size yet (auto-sizing), render invisible container for measurement
|
|
75
|
+
if (outerSize === 0) {
|
|
76
|
+
return <View style={{ flex: 1, aspectRatio: 1 }} onLayout={handleLayout} />;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const boardContent = (
|
|
80
|
+
<View
|
|
81
|
+
style={
|
|
82
|
+
isOutside
|
|
83
|
+
? { width: boardSize, height: boardSize, position: 'absolute', top: 0, right: 0 }
|
|
84
|
+
: { width: boardSize, height: boardSize }
|
|
85
|
+
}
|
|
86
|
+
onLayout={!isOutside && !boardSizeProp ? handleLayout : undefined}
|
|
87
|
+
accessibilityLabel="Chess board"
|
|
88
|
+
accessibilityRole="image"
|
|
89
|
+
>
|
|
90
|
+
{/* Layer 1: Board background */}
|
|
91
|
+
<BoardBackground
|
|
92
|
+
boardSize={boardSize}
|
|
93
|
+
lightColor={boardColors.light}
|
|
94
|
+
darkColor={boardColors.dark}
|
|
95
|
+
/>
|
|
96
|
+
|
|
97
|
+
{/* Layer 2: Inside coordinates */}
|
|
98
|
+
{isCoordVisible && !isOutside && (
|
|
99
|
+
<BoardCoordinates
|
|
100
|
+
boardSize={boardSize}
|
|
101
|
+
orientation={orientation}
|
|
102
|
+
lightColor={boardColors.light}
|
|
103
|
+
darkColor={boardColors.dark}
|
|
104
|
+
withLetters
|
|
105
|
+
withNumbers
|
|
106
|
+
position="inside"
|
|
107
|
+
/>
|
|
108
|
+
)}
|
|
109
|
+
|
|
110
|
+
{/* Layer 3: Highlights */}
|
|
111
|
+
<BoardHighlights
|
|
112
|
+
boardSize={boardSize}
|
|
113
|
+
orientation={orientation}
|
|
114
|
+
squareSize={squareSize}
|
|
115
|
+
lastMove={lastMove}
|
|
116
|
+
lastMoveColor={DEFAULT_LAST_MOVE_COLOR}
|
|
117
|
+
checkColor="transparent"
|
|
118
|
+
selectedColor="transparent"
|
|
119
|
+
premoveColor="transparent"
|
|
120
|
+
highlights={highlights}
|
|
121
|
+
/>
|
|
122
|
+
|
|
123
|
+
{/* Layer 4: Pieces (static — no animation needed) */}
|
|
124
|
+
<View
|
|
125
|
+
style={{ position: 'absolute', width: boardSize, height: boardSize }}
|
|
126
|
+
pointerEvents="none"
|
|
127
|
+
>
|
|
128
|
+
{pieces.map((piece) => {
|
|
129
|
+
const { x, y } = squareToXY(piece.square, squareSize, orientation);
|
|
130
|
+
return (
|
|
131
|
+
<View
|
|
132
|
+
key={piece.id}
|
|
133
|
+
style={{
|
|
134
|
+
position: 'absolute',
|
|
135
|
+
width: squareSize,
|
|
136
|
+
height: squareSize,
|
|
137
|
+
transform: [{ translateX: x }, { translateY: y }],
|
|
138
|
+
}}
|
|
139
|
+
>
|
|
140
|
+
{resolvedRenderer(piece.code, squareSize)}
|
|
141
|
+
</View>
|
|
142
|
+
);
|
|
143
|
+
})}
|
|
144
|
+
</View>
|
|
145
|
+
|
|
146
|
+
{/* Layer 5: Arrows */}
|
|
147
|
+
{arrows && arrows.length > 0 && (
|
|
148
|
+
<BoardArrows boardSize={boardSize} orientation={orientation} arrows={arrows} />
|
|
149
|
+
)}
|
|
150
|
+
|
|
151
|
+
{/* Layer 6: Annotations */}
|
|
152
|
+
{annotations && annotations.length > 0 && (
|
|
153
|
+
<BoardAnnotations
|
|
154
|
+
boardSize={boardSize}
|
|
155
|
+
orientation={orientation}
|
|
156
|
+
squareSize={squareSize}
|
|
157
|
+
annotations={annotations}
|
|
158
|
+
/>
|
|
159
|
+
)}
|
|
160
|
+
</View>
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
if (isOutside) {
|
|
164
|
+
return (
|
|
165
|
+
<View
|
|
166
|
+
style={{ width: outerSize, height: boardSize + gutterWidth }}
|
|
167
|
+
onLayout={boardSizeProp ? undefined : handleLayout}
|
|
168
|
+
>
|
|
169
|
+
{boardContent}
|
|
170
|
+
|
|
171
|
+
<BoardCoordinates
|
|
172
|
+
boardSize={boardSize}
|
|
173
|
+
orientation={orientation}
|
|
174
|
+
lightColor={boardColors.light}
|
|
175
|
+
darkColor={boardColors.dark}
|
|
176
|
+
withLetters
|
|
177
|
+
withNumbers
|
|
178
|
+
position="outside"
|
|
179
|
+
gutterWidth={gutterWidth}
|
|
180
|
+
/>
|
|
181
|
+
</View>
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return boardContent;
|
|
186
|
+
});
|
package/src/types.ts
CHANGED
|
@@ -25,8 +25,18 @@ export type HapticType = 'select' | 'move' | 'capture' | 'error';
|
|
|
25
25
|
|
|
26
26
|
/** Standard piece codes used throughout the library */
|
|
27
27
|
export type PieceCode =
|
|
28
|
-
| 'wp'
|
|
29
|
-
| '
|
|
28
|
+
| 'wp'
|
|
29
|
+
| 'wn'
|
|
30
|
+
| 'wb'
|
|
31
|
+
| 'wr'
|
|
32
|
+
| 'wq'
|
|
33
|
+
| 'wk'
|
|
34
|
+
| 'bp'
|
|
35
|
+
| 'bn'
|
|
36
|
+
| 'bb'
|
|
37
|
+
| 'br'
|
|
38
|
+
| 'bq'
|
|
39
|
+
| 'bk';
|
|
30
40
|
|
|
31
41
|
/** A single piece on the board with its position and identity */
|
|
32
42
|
export type BoardPiece = {
|
|
@@ -278,15 +288,26 @@ export type BoardProps = {
|
|
|
278
288
|
// --- Promotion ---
|
|
279
289
|
|
|
280
290
|
/**
|
|
281
|
-
*
|
|
282
|
-
*
|
|
291
|
+
* Auto-promote pawns to this piece without showing the picker.
|
|
292
|
+
* When set, the promotion picker is skipped entirely.
|
|
293
|
+
* Example: `autoPromoteTo="q"` always promotes to queen.
|
|
294
|
+
*/
|
|
295
|
+
autoPromoteTo?: PromotionPiece;
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Called when a pawn promotion occurs. If not provided, the built-in
|
|
299
|
+
* promotion picker is shown. Return the chosen piece to complete the
|
|
300
|
+
* promotion, or throw/reject to cancel.
|
|
301
|
+
*
|
|
302
|
+
* When provided, the built-in picker is NOT shown — the consumer is
|
|
303
|
+
* expected to handle piece selection via their own UI.
|
|
283
304
|
*/
|
|
284
305
|
onPromotion?: (from: string, to: string) => Promise<PromotionPiece> | PromotionPiece;
|
|
285
306
|
|
|
286
307
|
// --- Callbacks ---
|
|
287
308
|
|
|
288
|
-
/** Called after a visual move is applied */
|
|
289
|
-
onMove?: (info: { from: string; to: string }) => void;
|
|
309
|
+
/** Called after a visual move is applied. Includes `promotion` when a pawn promotes. */
|
|
310
|
+
onMove?: (info: { from: string; to: string; promotion?: PromotionPiece }) => void;
|
|
290
311
|
/** Called when a piece is tapped */
|
|
291
312
|
onPieceClick?: (square: string, piece: PieceCode) => void;
|
|
292
313
|
/** Called when an empty square or opponent piece is tapped */
|