kokopu-react 3.0.2 → 3.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/CHANGELOG.md +7 -1
- package/dist/lib/chessboard/BoardProperties.d.ts +91 -0
- package/dist/lib/chessboard/BoardProperties.js +43 -0
- package/dist/lib/chessboard/BoardProperties.js.map +1 -0
- package/dist/lib/chessboard/Chessboard.d.ts +14 -58
- package/dist/lib/chessboard/Chessboard.js +26 -92
- package/dist/lib/chessboard/Chessboard.js.map +1 -1
- package/dist/lib/errorbox/parsing.d.ts +57 -0
- package/dist/lib/errorbox/parsing.js +140 -0
- package/dist/lib/errorbox/parsing.js.map +1 -0
- package/dist/lib/i18n.d.ts +5 -0
- package/dist/lib/i18n.js +6 -0
- package/dist/lib/i18n.js.map +1 -1
- package/dist/lib/index.d.ts +4 -1
- package/dist/lib/index.js +2 -0
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/movetext/Movetext.css +0 -13
- package/dist/lib/movetext/Movetext.d.ts +9 -43
- package/dist/lib/movetext/Movetext.js +15 -67
- package/dist/lib/movetext/Movetext.js.map +1 -1
- package/dist/lib/movetext/MovetextImpl.d.ts +7 -28
- package/dist/lib/movetext/MovetextImpl.js +15 -94
- package/dist/lib/movetext/MovetextImpl.js.map +1 -1
- package/dist/lib/navigationboard/NavigationBoard.d.ts +118 -0
- package/dist/lib/navigationboard/NavigationBoard.js +112 -0
- package/dist/lib/navigationboard/NavigationBoard.js.map +1 -0
- package/dist/lib/navigationboard/NavigationField.css +36 -0
- package/dist/lib/navigationboard/NavigationField.d.ts +81 -0
- package/dist/lib/navigationboard/NavigationField.js +154 -0
- package/dist/lib/navigationboard/NavigationField.js.map +1 -0
- package/dist/lib/navigationboard/NavigationToolbar.css +51 -0
- package/dist/lib/navigationboard/NavigationToolbar.d.ts +41 -0
- package/dist/lib/navigationboard/NavigationToolbar.js +124 -0
- package/dist/lib/navigationboard/NavigationToolbar.js.map +1 -0
- package/doc_src/demo/PageChessboardMove.tsx +17 -0
- package/doc_src/demo/PageNavigationBoardBase.tsx +194 -0
- package/doc_src/demo/PageNavigationBoardUncontrolledVsControlled.tsx +114 -0
- package/doc_src/demo/game-3.pgn +10 -0
- package/doc_src/examples/Movetext.md +1 -1
- package/doc_src/examples/NavigationBoard.md +15 -0
- package/package.json +16 -16
- package/scripts/doc.styleguide.config.js +12 -2
- package/scripts/docker-compose.yml +1 -1
- package/src/chessboard/BoardProperties.ts +131 -0
- package/src/chessboard/Chessboard.tsx +41 -170
- package/src/errorbox/parsing.tsx +158 -0
- package/src/i18n.ts +7 -0
- package/src/index.ts +5 -1
- package/src/movetext/Movetext.css +0 -13
- package/src/movetext/Movetext.tsx +20 -85
- package/src/movetext/MovetextImpl.tsx +28 -115
- package/src/navigationboard/NavigationBoard.tsx +231 -0
- package/src/navigationboard/NavigationField.css +36 -0
- package/src/navigationboard/NavigationField.tsx +185 -0
- package/src/navigationboard/NavigationToolbar.css +51 -0
- package/src/navigationboard/NavigationToolbar.tsx +174 -0
- package/test/05_chessboard_graphic.js +2 -0
- package/test/09_chessboard_small_screens.js +21 -0
- package/test/10_movetext_graphic.js +5 -0
- package/test/11_movetext_interaction.js +12 -8
- package/test/12_navigation_board.js +168 -0
- package/test/graphic_references/05_chessboard_graphic/move/illegal_null-move.png +0 -0
- package/test/graphic_references/05_chessboard_graphic/move/null-move.png +0 -0
- package/test/graphic_references/09_chessboard_small_screens/top_bottom_components/default_bottom_component.png +0 -0
- package/test/graphic_references/09_chessboard_small_screens/top_bottom_components/default_top_component.png +0 -0
- package/test/graphic_references/09_chessboard_small_screens/top_bottom_components/reduced_bottom_component.png +0 -0
- package/test/graphic_references/09_chessboard_small_screens/top_bottom_components/reduced_top_component.png +0 -0
- package/test/graphic_references/10_movetext_graphic/format_move/format_text.png +0 -0
- package/test/graphic_references/10_movetext_graphic/options/wrong_piece_symbol_value.png +0 -0
- package/test/graphic_references/11_movetext_interaction/select_moves/click_on_unselected_without_callback.png +0 -0
- package/test/graphic_references/12_navigation_board/controlled/default.png +0 -0
- package/test/graphic_references/12_navigation_board/controlled/forbidden_navigation_0.png +0 -0
- package/test/graphic_references/12_navigation_board/controlled/forbidden_navigation_1.png +0 -0
- package/test/graphic_references/12_navigation_board/controlled/invalid_node_id.png +0 -0
- package/test/graphic_references/12_navigation_board/controlled/no_callback_defined_0.png +0 -0
- package/test/graphic_references/12_navigation_board/controlled/no_callback_defined_1.png +0 -0
- package/test/graphic_references/12_navigation_board/controlled/overriding_initial_node_id.png +0 -0
- package/test/graphic_references/12_navigation_board/controlled/regular_navigation_0.png +0 -0
- package/test/graphic_references/12_navigation_board/controlled/regular_navigation_1.png +0 -0
- package/test/graphic_references/12_navigation_board/controlled/regular_navigation_2.png +0 -0
- package/test/graphic_references/12_navigation_board/controlled/regular_navigation_3.png +0 -0
- package/test/graphic_references/12_navigation_board/error/pgn_parsing_error.png +0 -0
- package/test/graphic_references/12_navigation_board/error/wrong_game_type.png +0 -0
- package/test/graphic_references/12_navigation_board/theme/custom_1.png +0 -0
- package/test/graphic_references/12_navigation_board/theme/custom_2.png +0 -0
- package/test/graphic_references/12_navigation_board/theme/large.png +0 -0
- package/test/graphic_references/12_navigation_board/theme/small.png +0 -0
- package/test/graphic_references/12_navigation_board/uncontrolled/forbidden_navigation_at_beginning_0.png +0 -0
- package/test/graphic_references/12_navigation_board/uncontrolled/forbidden_navigation_at_beginning_1.png +0 -0
- package/test/graphic_references/12_navigation_board/uncontrolled/forbidden_navigation_at_beginning_2.png +0 -0
- package/test/graphic_references/12_navigation_board/uncontrolled/forbidden_navigation_at_end_0.png +0 -0
- package/test/graphic_references/12_navigation_board/uncontrolled/forbidden_navigation_at_end_1.png +0 -0
- package/test/graphic_references/12_navigation_board/uncontrolled/forbidden_navigation_at_end_2.png +0 -0
- package/test/graphic_references/12_navigation_board/uncontrolled/initial_state_at_end.png +0 -0
- package/test/graphic_references/12_navigation_board/uncontrolled/initial_state_at_specific_id.png +0 -0
- package/test/graphic_references/12_navigation_board/uncontrolled/initial_state_default.png +0 -0
- package/test/graphic_references/12_navigation_board/uncontrolled/initial_state_default_with_game_index.png +0 -0
- package/test/graphic_references/12_navigation_board/uncontrolled/initial_state_on_null-move.png +0 -0
- package/test/graphic_references/12_navigation_board/uncontrolled/navigation_with_keys_0.png +0 -0
- package/test/graphic_references/12_navigation_board/uncontrolled/navigation_with_keys_1.png +0 -0
- package/test/graphic_references/12_navigation_board/uncontrolled/navigation_with_keys_2.png +0 -0
- package/test/graphic_references/12_navigation_board/uncontrolled/navigation_with_keys_3.png +0 -0
- package/test/graphic_references/12_navigation_board/uncontrolled/navigation_with_keys_4.png +0 -0
- package/test/graphic_references/12_navigation_board/uncontrolled/regular_flipping_0.png +0 -0
- package/test/graphic_references/12_navigation_board/uncontrolled/regular_flipping_1.png +0 -0
- package/test/graphic_references/12_navigation_board/uncontrolled/regular_navigation_0.png +0 -0
- package/test/graphic_references/12_navigation_board/uncontrolled/regular_navigation_1.png +0 -0
- package/test/graphic_references/12_navigation_board/uncontrolled/regular_navigation_2.png +0 -0
- package/test/graphic_references/12_navigation_board/uncontrolled/regular_navigation_3.png +0 -0
- package/test/graphic_references/12_navigation_board/uncontrolled/regular_navigation_4.png +0 -0
- package/test/graphic_references/12_navigation_board/uncontrolled/regular_navigation_5.png +0 -0
- package/test/graphic_test_app/05_chessboard_graphic/move.tsx +2 -0
- package/test/graphic_test_app/09_chessboard_small_screens/top_bottom_components.tsx +48 -0
- package/test/graphic_test_app/10_movetext_graphic/format_move.tsx +31 -0
- package/test/graphic_test_app/10_movetext_graphic/options.tsx +1 -0
- package/test/graphic_test_app/11_movetext_interaction/select_moves.tsx +1 -0
- package/test/graphic_test_app/12_navigation_board/controlled.tsx +43 -0
- package/test/graphic_test_app/12_navigation_board/error.tsx +34 -0
- package/test/graphic_test_app/12_navigation_board/theme.tsx +38 -0
- package/test/graphic_test_app/12_navigation_board/uncontrolled.tsx +56 -0
|
@@ -24,32 +24,21 @@
|
|
|
24
24
|
|
|
25
25
|
import * as React from 'react';
|
|
26
26
|
|
|
27
|
-
import {
|
|
27
|
+
import { MoveDescriptor, Position, Square, isSquare, isSquareCouple } from 'kokopu';
|
|
28
28
|
|
|
29
29
|
import { IllegalArgument } from '../exception';
|
|
30
|
-
import { i18n } from '../i18n';
|
|
31
30
|
import { sanitizeString, sanitizeBoolean, sanitizePartialObject, sanitizeInteger, sanitizeBoundedInteger, sanitizeOptional } from '../sanitization';
|
|
32
31
|
import { MIN_SQUARE_SIZE, MAX_SQUARE_SIZE, Colorset, Pieceset, AnnotationColor, AnnotationSymbol, SquareMarkerSet, TextMarkerSet, ArrowMarkerSet,
|
|
33
32
|
isAnnotationColor, isAnnotationSymbol, parseSquareMarkers, parseTextMarkers, parseArrowMarkers } from '../types';
|
|
34
33
|
|
|
35
|
-
import {
|
|
36
|
-
import {
|
|
34
|
+
import { StaticBoardGraphicProps, DynamicBoardGraphicProps, SmallScreenLimit, DEFAULT_SQUARE_SIZE, defaultDynamicBoardProps } from './BoardProperties';
|
|
35
|
+
import { colorsets } from './colorsets';
|
|
36
|
+
import { piecesets } from './piecesets';
|
|
37
37
|
import { ChessboardImpl, chessboardSize } from './ChessboardImpl';
|
|
38
|
-
import {
|
|
38
|
+
import { parsePosition, parseMove } from '../errorbox/parsing';
|
|
39
39
|
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
* Define a limit applicable to the parameters of a {@link Chessboard} on small-screen devices.
|
|
43
|
-
*/
|
|
44
|
-
export interface SmallScreenLimit {
|
|
45
|
-
width: number;
|
|
46
|
-
squareSize?: number;
|
|
47
|
-
coordinateVisible?: boolean;
|
|
48
|
-
turnVisible?: boolean;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
export interface ChessboardProps {
|
|
41
|
+
export interface ChessboardProps extends DynamicBoardGraphicProps {
|
|
53
42
|
|
|
54
43
|
/**
|
|
55
44
|
* Displayed position. Can be a [kokopu.Position](https://kokopu.yo35.org/docs/current/classes/Position.html) object,
|
|
@@ -64,8 +53,8 @@ export interface ChessboardProps {
|
|
|
64
53
|
|
|
65
54
|
/**
|
|
66
55
|
* Displayed move (optional), defined either as a [kokopu.MoveDescriptor](https://kokopu.yo35.org/docs/current/classes/MoveDescriptor.html) object
|
|
67
|
-
* or as a [SAN string](https://en.wikipedia.org/wiki/Algebraic_notation_(chess)) (e.g. `'Nf3'`).
|
|
68
|
-
* a legal move in position defined in attribute `position`.
|
|
56
|
+
* or as a [SAN string](https://en.wikipedia.org/wiki/Algebraic_notation_(chess)) (e.g. `'Nf3'`). Use `'--'` for a null-move.
|
|
57
|
+
* In all cases, the move must be a legal move in position defined in attribute `position`.
|
|
69
58
|
*/
|
|
70
59
|
move?: MoveDescriptor | string;
|
|
71
60
|
|
|
@@ -91,61 +80,6 @@ export interface ChessboardProps {
|
|
|
91
80
|
*/
|
|
92
81
|
flipped: boolean;
|
|
93
82
|
|
|
94
|
-
/**
|
|
95
|
-
* Size of the squares (in pixels). Must be an integer between `Chessboard.minSquareSize()` and `Chessboard.maxSquareSize()`.
|
|
96
|
-
*/
|
|
97
|
-
squareSize: number;
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* Whether the row and column coordinates are visible or not.
|
|
101
|
-
*/
|
|
102
|
-
coordinateVisible: boolean;
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Whether the turn flag is visible or not.
|
|
106
|
-
*/
|
|
107
|
-
turnVisible: boolean;
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* Whether moves are highlighted with an arrow or not.
|
|
111
|
-
*/
|
|
112
|
-
moveArrowVisible: boolean;
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* Color of the move arrow.
|
|
116
|
-
*/
|
|
117
|
-
moveArrowColor: AnnotationColor;
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* Whether moves are animated or not.
|
|
121
|
-
*/
|
|
122
|
-
animated: boolean;
|
|
123
|
-
|
|
124
|
-
/**
|
|
125
|
-
* Color theme ID. Must be a property of `Chessboard.colorsets()`.
|
|
126
|
-
*/
|
|
127
|
-
colorset: string;
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* Piece theme ID. Must be a property of `Chessboard.piecesets()`.
|
|
131
|
-
*/
|
|
132
|
-
pieceset: string;
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Limits applicable on small-screen devices. For instance, if set to
|
|
136
|
-
* ```
|
|
137
|
-
* [
|
|
138
|
-
* { width: 768, squareSize: 40 },
|
|
139
|
-
* { width: 375, squareSize: 24, coordinateVisible: false }
|
|
140
|
-
* ]
|
|
141
|
-
* ```
|
|
142
|
-
* then on screens with resolution ≤768 pixels, the square size will be limited to 40 (whatever the value
|
|
143
|
-
* of the `squareSize` attribute); in addition, on screens with resolution ≤375 pixels, the square size
|
|
144
|
-
* will be limited to 24 and the row and column coordinates will always be hidden (whatever the value of the
|
|
145
|
-
* `coordinateVisible` attribute).
|
|
146
|
-
*/
|
|
147
|
-
smallScreenLimits?: SmallScreenLimit[];
|
|
148
|
-
|
|
149
83
|
/**
|
|
150
84
|
* Type of action allowed with the mouse on the chessboard. If undefined, then the user cannot interact with the component.
|
|
151
85
|
*
|
|
@@ -180,6 +114,18 @@ export interface ChessboardProps {
|
|
|
180
114
|
* Callback invoked when a move is played (only if `interactionMode` is set to `'playMoves'`).
|
|
181
115
|
*/
|
|
182
116
|
onMovePlayed?: (move: string) => void;
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Optional component, to be rendered above the chessboard, and customized with the same square-size / coordinate-visible / turn-visible
|
|
120
|
+
* parameter values as actually used for the chessboard (which may be different from what is defined in props because of small-screen limits).
|
|
121
|
+
*/
|
|
122
|
+
topComponent?: (attr: Pick<StaticBoardGraphicProps, 'squareSize' | 'coordinateVisible' | 'turnVisible'>) => JSX.Element;
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Optional component, to be rendered below the chessboard, and customized with the same square-size / coordinate-visible / turn-visible
|
|
126
|
+
* parameter values as actually used for the chessboard (which may be different from what is defined in props because of small-screen limits).
|
|
127
|
+
*/
|
|
128
|
+
bottomComponent?: (attr: Pick<StaticBoardGraphicProps, 'squareSize' | 'coordinateVisible' | 'turnVisible'>) => JSX.Element;
|
|
183
129
|
}
|
|
184
130
|
|
|
185
131
|
|
|
@@ -188,9 +134,6 @@ interface ChessboardState {
|
|
|
188
134
|
}
|
|
189
135
|
|
|
190
136
|
|
|
191
|
-
const DEFAULT_SQUARE_SIZE = 40;
|
|
192
|
-
|
|
193
|
-
|
|
194
137
|
/**
|
|
195
138
|
* SVG image representing a chessboard diagram. Optionally, the user may interact with the board (move pieces, click on squares...).
|
|
196
139
|
* Annotations such as square markers or arrows can also be added to the board.
|
|
@@ -198,16 +141,9 @@ const DEFAULT_SQUARE_SIZE = 40;
|
|
|
198
141
|
export class Chessboard extends React.Component<ChessboardProps, ChessboardState> {
|
|
199
142
|
|
|
200
143
|
static defaultProps: Partial<ChessboardProps> = {
|
|
144
|
+
...defaultDynamicBoardProps(),
|
|
201
145
|
position: 'start',
|
|
202
146
|
flipped: false,
|
|
203
|
-
squareSize: DEFAULT_SQUARE_SIZE,
|
|
204
|
-
coordinateVisible: true,
|
|
205
|
-
turnVisible: true,
|
|
206
|
-
moveArrowVisible: true,
|
|
207
|
-
moveArrowColor: 'b',
|
|
208
|
-
animated: false,
|
|
209
|
-
colorset: DEFAULT_COLORSET,
|
|
210
|
-
pieceset: DEFAULT_PIECESET,
|
|
211
147
|
};
|
|
212
148
|
|
|
213
149
|
private windowResizeListener = () => this.handleWindowResize();
|
|
@@ -234,16 +170,20 @@ export class Chessboard extends React.Component<ChessboardProps, ChessboardState
|
|
|
234
170
|
render() {
|
|
235
171
|
|
|
236
172
|
// Validate the position and move attributes.
|
|
237
|
-
const positionInfo = parsePosition(this.props.position);
|
|
173
|
+
const positionInfo = parsePosition(this.props.position, 'Chessboard');
|
|
238
174
|
if (positionInfo.error) {
|
|
239
|
-
return
|
|
175
|
+
return positionInfo.errorBox;
|
|
240
176
|
}
|
|
241
|
-
|
|
242
|
-
const moveInfo = parseMove(position, this.props.move);
|
|
177
|
+
let position = positionInfo.position;
|
|
178
|
+
const moveInfo = parseMove(position, this.props.move, 'Chessboard');
|
|
243
179
|
if (moveInfo.error) {
|
|
244
|
-
return
|
|
180
|
+
return moveInfo.errorBox;
|
|
181
|
+
}
|
|
182
|
+
const move = moveInfo.type === 'regular' ? moveInfo.move : undefined;
|
|
183
|
+
if (moveInfo.type === 'null-move') {
|
|
184
|
+
position = new Position(position);
|
|
185
|
+
position.playNullMove();
|
|
245
186
|
}
|
|
246
|
-
const move = moveInfo.move;
|
|
247
187
|
|
|
248
188
|
// Validate the markers
|
|
249
189
|
const sqm = parseMarkers(this.props.squareMarkers, 'squareMarkers', parseSquareMarkers, isSquare, isAnnotationColor);
|
|
@@ -274,6 +214,11 @@ export class Chessboard extends React.Component<ChessboardProps, ChessboardState
|
|
|
274
214
|
const actualSquareSize = computeSquareSizeForSmallScreens(squareSize, smallScreenLimits, this.state.windowWidth);
|
|
275
215
|
const actualCoordinateVisible = computeCoordinateVisibleForSmallScreens(coordinateVisible, smallScreenLimits, this.state.windowWidth);
|
|
276
216
|
const actualTurnVisible = computeTurnVisibleForSmallScreens(turnVisible, smallScreenLimits, this.state.windowWidth);
|
|
217
|
+
const auxilliaryComponentAttr = {
|
|
218
|
+
squareSize: actualSquareSize,
|
|
219
|
+
coordinateVisible: actualCoordinateVisible,
|
|
220
|
+
turnVisible: actualTurnVisible,
|
|
221
|
+
};
|
|
277
222
|
|
|
278
223
|
// Validate the interaction attributes and the callbacks.
|
|
279
224
|
const interactionMode = this.getInteractionModeAndValidateEditedArrowColor();
|
|
@@ -283,7 +228,8 @@ export class Chessboard extends React.Component<ChessboardProps, ChessboardState
|
|
|
283
228
|
// (mandatory to ensure that the move animation works properly and that the internal state of the component remains consistent).
|
|
284
229
|
const key = `${position.variant()}|${position.fen()}|${move ? position.notation(move) : ''}`;
|
|
285
230
|
|
|
286
|
-
return (
|
|
231
|
+
return (<>
|
|
232
|
+
{this.props.topComponent ? this.props.topComponent(auxilliaryComponentAttr) : undefined}
|
|
287
233
|
<ChessboardImpl key={key}
|
|
288
234
|
position={position} move={move} squareMarkers={sqm} textMarkers={txtm} arrowMarkers={arm} flipped={flipped}
|
|
289
235
|
squareSize={actualSquareSize} coordinateVisible={actualCoordinateVisible} turnVisible={actualTurnVisible}
|
|
@@ -292,7 +238,8 @@ export class Chessboard extends React.Component<ChessboardProps, ChessboardState
|
|
|
292
238
|
interactionMode={interactionMode} editedArrowColor={this.props.editedArrowColor}
|
|
293
239
|
onPieceMoved={onPieceMoved} onSquareClicked={onSquareClicked} onArrowEdited={onArrowEdited} onMovePlayed={onMovePlayed}
|
|
294
240
|
/>
|
|
295
|
-
|
|
241
|
+
{this.props.bottomComponent ? this.props.bottomComponent(auxilliaryComponentAttr) : undefined}
|
|
242
|
+
</>);
|
|
296
243
|
}
|
|
297
244
|
|
|
298
245
|
private getInteractionModeAndValidateEditedArrowColor() {
|
|
@@ -339,7 +286,7 @@ export class Chessboard extends React.Component<ChessboardProps, ChessboardState
|
|
|
339
286
|
* Return the maximum square size that would allow the chessboard to fit in a rectangle of size `width x height`.
|
|
340
287
|
*/
|
|
341
288
|
static adaptSquareSize(width: number, height: number, attr?: Partial<Pick<ChessboardProps, 'coordinateVisible' | 'turnVisible' | 'smallScreenLimits'>>): number {
|
|
342
|
-
let { coordinateVisible, turnVisible, smallScreenLimits } = sanitizePartialObject(attr, () => new IllegalArgument('Chessboard.
|
|
289
|
+
let { coordinateVisible, turnVisible, smallScreenLimits } = sanitizePartialObject(attr, () => new IllegalArgument('Chessboard.adaptSquareSize()', 'attr'));
|
|
343
290
|
|
|
344
291
|
// Sanitize the arguments.
|
|
345
292
|
width = sanitizeInteger(width, () => new IllegalArgument('Chessboard.adaptSquareSize()', 'width'));
|
|
@@ -473,82 +420,6 @@ function computeSmallScreenLimits<T>(smallScreenLimits: SmallScreenLimit[], wind
|
|
|
473
420
|
}
|
|
474
421
|
|
|
475
422
|
|
|
476
|
-
/**
|
|
477
|
-
* Try to interpret the given object as a chess position.
|
|
478
|
-
*/
|
|
479
|
-
function parsePosition(position: Position | string): { error: true, message: string } | { error: false, position: Position } {
|
|
480
|
-
if (position instanceof Position) {
|
|
481
|
-
return { error: false, position: position };
|
|
482
|
-
}
|
|
483
|
-
else if (position === 'start' || position === 'empty') {
|
|
484
|
-
return { error: false, position: new Position(position) };
|
|
485
|
-
}
|
|
486
|
-
else if (typeof position === 'string') {
|
|
487
|
-
try {
|
|
488
|
-
const { variant, fen } = splitGameVariantAndFEN(position);
|
|
489
|
-
const result = new Position(variant, 'empty');
|
|
490
|
-
result.fen(fen);
|
|
491
|
-
return { error: false, position: result };
|
|
492
|
-
}
|
|
493
|
-
catch (e) {
|
|
494
|
-
// istanbul ignore else
|
|
495
|
-
if (e instanceof kokopuException.InvalidFEN) {
|
|
496
|
-
return { error: true, message: e.message };
|
|
497
|
-
}
|
|
498
|
-
else {
|
|
499
|
-
throw e;
|
|
500
|
-
}
|
|
501
|
-
}
|
|
502
|
-
}
|
|
503
|
-
else {
|
|
504
|
-
throw new IllegalArgument('Chessboard', 'position');
|
|
505
|
-
}
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
/**
|
|
510
|
-
* Look for an optional 'chess-variant:' prefix in the position attribute.
|
|
511
|
-
*/
|
|
512
|
-
function splitGameVariantAndFEN(position: string): { variant: GameVariant, fen: string } {
|
|
513
|
-
const separatorIndex = position.indexOf(':');
|
|
514
|
-
if (separatorIndex < 0) {
|
|
515
|
-
return { variant: 'regular', fen: position };
|
|
516
|
-
}
|
|
517
|
-
const variant = position.substring(0, separatorIndex);
|
|
518
|
-
return isGameVariant(variant) ? { variant: variant, fen: position.substring(separatorIndex + 1) } : { variant: 'regular', fen: position };
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
/**
|
|
523
|
-
* Try to interpret the given object `move` as a move descriptor based on the given position.
|
|
524
|
-
*/
|
|
525
|
-
function parseMove(position: Position, move: MoveDescriptor | string | undefined): { error: true, message: string } | { error: false, move: MoveDescriptor | undefined } {
|
|
526
|
-
if (move === undefined || move === null) {
|
|
527
|
-
return { error: false, move: undefined };
|
|
528
|
-
}
|
|
529
|
-
else if (move instanceof MoveDescriptor) {
|
|
530
|
-
return { error: false, move: move };
|
|
531
|
-
}
|
|
532
|
-
else if (typeof move === 'string') {
|
|
533
|
-
try {
|
|
534
|
-
return { error: false, move: position.notation(move) };
|
|
535
|
-
}
|
|
536
|
-
catch (e) {
|
|
537
|
-
// istanbul ignore else
|
|
538
|
-
if (e instanceof kokopuException.InvalidNotation) {
|
|
539
|
-
return { error: true, message: e.message };
|
|
540
|
-
}
|
|
541
|
-
else {
|
|
542
|
-
throw e;
|
|
543
|
-
}
|
|
544
|
-
}
|
|
545
|
-
}
|
|
546
|
-
else {
|
|
547
|
-
throw new IllegalArgument('Chessboard', 'move');
|
|
548
|
-
}
|
|
549
|
-
}
|
|
550
|
-
|
|
551
|
-
|
|
552
423
|
/**
|
|
553
424
|
* Try to interpret the given object as a list of markers.
|
|
554
425
|
*/
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* -------------------------------------------------------------------------- *
|
|
3
|
+
* *
|
|
4
|
+
* Kokopu-React - A React-based library of chess-related components. *
|
|
5
|
+
* <https://www.npmjs.com/package/kokopu-react> *
|
|
6
|
+
* Copyright (C) 2021-2024 Yoann Le Montagner <yo35 -at- melix.net> *
|
|
7
|
+
* *
|
|
8
|
+
* Kokopu-React is free software: you can redistribute it and/or *
|
|
9
|
+
* modify it under the terms of the GNU Lesser General Public License *
|
|
10
|
+
* as published by the Free Software Foundation, either version 3 of *
|
|
11
|
+
* the License, or (at your option) any later version. *
|
|
12
|
+
* *
|
|
13
|
+
* Kokopu-React is distributed in the hope that it will be useful, *
|
|
14
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
15
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
16
|
+
* GNU Lesser General Public License for more details. *
|
|
17
|
+
* *
|
|
18
|
+
* You should have received a copy of the GNU Lesser General *
|
|
19
|
+
* Public License along with this program. If not, see *
|
|
20
|
+
* <http://www.gnu.org/licenses/>. *
|
|
21
|
+
* *
|
|
22
|
+
* -------------------------------------------------------------------------- */
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
import * as React from 'react';
|
|
26
|
+
|
|
27
|
+
import { exception as kokopuException, i18n as kokopuI18n, Database, Game, GameVariant, MoveDescriptor, Position, isGameVariant, pgnRead } from 'kokopu';
|
|
28
|
+
|
|
29
|
+
import { IllegalArgument } from '../exception';
|
|
30
|
+
import { i18n } from '../i18n';
|
|
31
|
+
|
|
32
|
+
import { ErrorBox } from './ErrorBox';
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Try to interpret the given object as a chess position.
|
|
37
|
+
*/
|
|
38
|
+
export function parsePosition(position: Position | string, componentName: string):
|
|
39
|
+
{ error: true, errorBox: JSX.Element } | { error: false, position: Position }
|
|
40
|
+
{
|
|
41
|
+
if (position instanceof Position) {
|
|
42
|
+
return { error: false, position: position };
|
|
43
|
+
}
|
|
44
|
+
else if (position === 'start' || position === 'empty') {
|
|
45
|
+
return { error: false, position: new Position(position) };
|
|
46
|
+
}
|
|
47
|
+
else if (typeof position === 'string') {
|
|
48
|
+
try {
|
|
49
|
+
const { variant, fen } = splitGameVariantAndFEN(position);
|
|
50
|
+
const result = new Position(variant, 'empty');
|
|
51
|
+
result.fen(fen);
|
|
52
|
+
return { error: false, position: result };
|
|
53
|
+
}
|
|
54
|
+
catch (e) {
|
|
55
|
+
// istanbul ignore else
|
|
56
|
+
if (e instanceof kokopuException.InvalidFEN) {
|
|
57
|
+
return { error: true, errorBox: <ErrorBox title={i18n.INVALID_FEN_ERROR_TITLE} message={e.message} /> };
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
throw e;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
throw new IllegalArgument(componentName, 'position');
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Look for an optional 'chess-variant:' prefix in the position attribute.
|
|
72
|
+
*/
|
|
73
|
+
function splitGameVariantAndFEN(position: string): { variant: GameVariant, fen: string } {
|
|
74
|
+
const separatorIndex = position.indexOf(':');
|
|
75
|
+
if (separatorIndex < 0) {
|
|
76
|
+
return { variant: 'regular', fen: position };
|
|
77
|
+
}
|
|
78
|
+
const variant = position.substring(0, separatorIndex);
|
|
79
|
+
return isGameVariant(variant) ? { variant: variant, fen: position.substring(separatorIndex + 1) } : { variant: 'regular', fen: position };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Try to interpret the given object `move` as a move descriptor based on the given position.
|
|
85
|
+
*/
|
|
86
|
+
export function parseMove(position: Position, move: MoveDescriptor | string | undefined, componentName: string):
|
|
87
|
+
{ error: true, errorBox: JSX.Element } | { error: false, type: 'none' | 'null-move' } | { error: false, type: 'regular', move: MoveDescriptor }
|
|
88
|
+
{
|
|
89
|
+
if (move === undefined || move === null) {
|
|
90
|
+
return { error: false, type: 'none' };
|
|
91
|
+
}
|
|
92
|
+
else if (move instanceof MoveDescriptor) {
|
|
93
|
+
return { error: false, type: 'regular', move: move };
|
|
94
|
+
}
|
|
95
|
+
else if (typeof move === 'string') {
|
|
96
|
+
if (move === '--') {
|
|
97
|
+
if (position.isNullMoveLegal()) {
|
|
98
|
+
return { error: false, type: 'null-move' };
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
return { error: true, errorBox: <ErrorBox title={i18n.INVALID_NOTATION_ERROR_TITLE} message={kokopuI18n.ILLEGAL_NULL_MOVE} /> };
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
try {
|
|
106
|
+
return { error: false, type: 'regular', move: position.notation(move) };
|
|
107
|
+
}
|
|
108
|
+
catch (e) {
|
|
109
|
+
// istanbul ignore else
|
|
110
|
+
if (e instanceof kokopuException.InvalidNotation) {
|
|
111
|
+
return { error: true, errorBox: <ErrorBox title={i18n.INVALID_NOTATION_ERROR_TITLE} message={e.message} /> };
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
throw e;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
throw new IllegalArgument(componentName, 'move');
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Try to interpret the given object as a chess game.
|
|
127
|
+
*/
|
|
128
|
+
export function parseGame(game: Game | Database | string, gameIndex: number, componentName: string):
|
|
129
|
+
{ error: true, errorBox: JSX.Element } | { error: false, game: Game }
|
|
130
|
+
{
|
|
131
|
+
if (game instanceof Game) {
|
|
132
|
+
return { error: false, game: game };
|
|
133
|
+
}
|
|
134
|
+
else if (game instanceof Database || typeof game === 'string') {
|
|
135
|
+
if (!Number.isInteger(gameIndex) || gameIndex < 0) {
|
|
136
|
+
throw new IllegalArgument(componentName, 'gameIndex');
|
|
137
|
+
}
|
|
138
|
+
try {
|
|
139
|
+
const result = game instanceof Database ? game.game(gameIndex) : pgnRead(game, gameIndex);
|
|
140
|
+
return { error: false, game: result };
|
|
141
|
+
}
|
|
142
|
+
catch (e) {
|
|
143
|
+
// istanbul ignore else
|
|
144
|
+
if (e instanceof kokopuException.InvalidPGN) {
|
|
145
|
+
return {
|
|
146
|
+
error: true,
|
|
147
|
+
errorBox: <ErrorBox title={i18n.INVALID_PGN_ERROR_TITLE} message={e.message} text={e.pgn} errorIndex={e.index} lineNumber={e.lineNumber} />,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
throw e;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
throw new IllegalArgument(componentName, 'game');
|
|
157
|
+
}
|
|
158
|
+
}
|
package/src/i18n.ts
CHANGED
|
@@ -37,6 +37,13 @@ export let LINE = 'line {0}';
|
|
|
37
37
|
export let INVALID_FEN_ERROR_TITLE = 'Invalid FEN string.';
|
|
38
38
|
export let INVALID_NOTATION_ERROR_TITLE = 'Invalid move notation.';
|
|
39
39
|
|
|
40
|
+
// Navigation board
|
|
41
|
+
export let TOOLTIP_GO_FIRST = 'Go to the beginning of the game';
|
|
42
|
+
export let TOOLTIP_GO_PREVIOUS = 'Go to the previous move';
|
|
43
|
+
export let TOOLTIP_GO_NEXT = 'Go to the next move';
|
|
44
|
+
export let TOOLTIP_GO_LAST = 'Go to the end of the game';
|
|
45
|
+
export let TOOLTIP_FLIP = 'Flip the board';
|
|
46
|
+
|
|
40
47
|
// Movetext
|
|
41
48
|
export let PIECE_SYMBOLS = { 'K':'K', 'Q':'Q', 'R':'R', 'B':'B', 'N':'N', 'P':'P' };
|
|
42
49
|
export let ANNOTATED_BY = 'Annotated by {0}';
|
package/src/index.ts
CHANGED
|
@@ -36,7 +36,11 @@ export { TextMarkerIcon, TextMarkerIconProps } from './icons/TextMarkerIcon';
|
|
|
36
36
|
export { ArrowMarkerIcon, ArrowMarkerIconProps } from './icons/ArrowMarkerIcon';
|
|
37
37
|
export { ChessPieceIcon, ChessPieceIconProps } from './icons/ChessPieceIcon';
|
|
38
38
|
|
|
39
|
-
export {
|
|
39
|
+
export { SmallScreenLimit } from './chessboard/BoardProperties';
|
|
40
|
+
export { Chessboard, ChessboardProps } from './chessboard/Chessboard';
|
|
40
41
|
|
|
41
42
|
export { formatMove, moveFormatter } from './movetext/moveFormatter';
|
|
42
43
|
export { Movetext, MovetextProps, MoveSelectEventOrigin } from './movetext/Movetext';
|
|
44
|
+
|
|
45
|
+
export { firstNodeId, previousNodeId, nextNodeId, lastNodeId } from './navigationboard/NavigationField';
|
|
46
|
+
export { NavigationBoard, NavigationBoardProps } from './navigationboard/NavigationBoard';
|
|
@@ -108,16 +108,3 @@ div.kokopu-subVariation {
|
|
|
108
108
|
text-decoration: underline;
|
|
109
109
|
cursor: pointer;
|
|
110
110
|
}
|
|
111
|
-
|
|
112
|
-
.kokopu-focusFieldContainer {
|
|
113
|
-
position: fixed;
|
|
114
|
-
bottom: 0px;
|
|
115
|
-
right: 0px;
|
|
116
|
-
width: 0px;
|
|
117
|
-
height: 0px;
|
|
118
|
-
overflow: hidden;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
.kokopu-focusField {
|
|
122
|
-
position: absolute; /* see #1 */
|
|
123
|
-
}
|