kokopu-react 3.0.2 → 3.2.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/.eslintrc.yml +1 -1
- package/CHANGELOG.md +13 -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.css +13 -13
- 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/chessboard/ChessboardImpl.js.map +1 -1
- package/dist/lib/chessboard/Draggable.js.map +1 -1
- package/dist/lib/chessboard/Motion.js.map +1 -1
- package/dist/lib/chessboard/colorsets.js.map +1 -1
- package/dist/lib/chessboard/piecesets.js.map +1 -1
- package/dist/lib/errorbox/ErrorBox.css +18 -18
- package/dist/lib/errorbox/ErrorBox.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/exception.js.map +1 -1
- package/dist/lib/i18n.d.ts +6 -0
- package/dist/lib/i18n.js +7 -0
- package/dist/lib/i18n.js.map +1 -1
- package/dist/lib/icons/AnnotationSymbolShape.css +6 -6
- package/dist/lib/icons/AnnotationSymbolShape.js.map +1 -1
- package/dist/lib/icons/ArrowMarkerIcon.js.map +1 -1
- package/dist/lib/icons/ArrowTip.js.map +1 -1
- package/dist/lib/icons/ChessPieceIcon.js.map +1 -1
- package/dist/lib/icons/SquareMarkerIcon.js.map +1 -1
- package/dist/lib/icons/TextMarkerIcon.js.map +1 -1
- package/dist/lib/icons/arrow.css +1 -1
- package/dist/lib/index.d.ts +5 -1
- package/dist/lib/index.js +3 -0
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/movetext/Movetext.css +27 -40
- 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/movetext/fonts.css +7 -7
- package/dist/lib/movetext/htmlFilter.js.map +1 -1
- package/dist/lib/movetext/moveFormatter.js.map +1 -1
- package/dist/lib/navigationboard/NavigationBoard.d.ts +156 -0
- package/dist/lib/navigationboard/NavigationBoard.js +195 -0
- package/dist/lib/navigationboard/NavigationBoard.js.map +1 -0
- package/dist/lib/navigationboard/NavigationButton.d.ts +54 -0
- package/dist/lib/navigationboard/NavigationButton.js +35 -0
- package/dist/lib/navigationboard/NavigationButton.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 +54 -0
- package/dist/lib/navigationboard/NavigationToolbar.d.ts +34 -0
- package/dist/lib/navigationboard/NavigationToolbar.js +73 -0
- package/dist/lib/navigationboard/NavigationToolbar.js.map +1 -0
- package/dist/lib/navigationboard/iconPaths.d.ts +29 -0
- package/dist/lib/navigationboard/iconPaths.js +91 -0
- package/dist/lib/navigationboard/iconPaths.js.map +1 -0
- package/dist/lib/sanitization.js.map +1 -1
- package/dist/lib/types.js.map +1 -1
- package/dist/lib/util.js.map +1 -1
- package/doc_src/demo/PageChessboardBase.tsx +115 -115
- package/doc_src/demo/PageChessboardInteraction.tsx +303 -303
- package/doc_src/demo/PageChessboardMove.tsx +173 -156
- package/doc_src/demo/PageChessboardSmallScreens.tsx +94 -94
- package/doc_src/demo/PageMovetextBase.tsx +180 -180
- package/doc_src/demo/PageMovetextInteraction.tsx +123 -123
- package/doc_src/demo/PageNavigationBoardBase.tsx +201 -0
- package/doc_src/demo/PageNavigationBoardUncontrolledVsControlled.tsx +114 -0
- package/doc_src/demo/decs.d.ts +4 -4
- package/doc_src/demo/demo.css +12 -12
- package/doc_src/demo/game-3.pgn +10 -0
- package/doc_src/demo/util.ts +1 -1
- package/doc_src/examples/Movetext.md +1 -1
- package/doc_src/examples/NavigationBoard.md +15 -0
- package/doc_src/theming/LogoRenderer.js +13 -13
- package/doc_src/theming/theming.css +5 -5
- package/package.json +95 -95
- package/scripts/doc.styleguide.config.js +133 -123
- package/scripts/doc.tsconfig.json +5 -5
- package/scripts/docker-compose.yml +1 -1
- package/scripts/test-graphic.tsconfig.json +5 -5
- package/scripts/test-graphic.webpack.config.js +57 -57
- package/scripts/test-headless.webpack.config.js +29 -29
- package/src/chessboard/BoardProperties.ts +131 -0
- package/src/chessboard/Chessboard.css +13 -13
- package/src/chessboard/Chessboard.tsx +389 -518
- package/src/chessboard/ChessboardImpl.tsx +557 -557
- package/src/chessboard/Draggable.tsx +185 -185
- package/src/chessboard/Motion.tsx +67 -67
- package/src/chessboard/colorsets.ts +66 -66
- package/src/chessboard/piecesets.ts +84 -84
- package/src/decs.d.ts +2 -2
- package/src/errorbox/ErrorBox.css +18 -18
- package/src/errorbox/ErrorBox.tsx +75 -75
- package/src/errorbox/parsing.tsx +158 -0
- package/src/exception.ts +17 -17
- package/src/i18n.ts +8 -0
- package/src/icons/AnnotationSymbolShape.css +6 -6
- package/src/icons/AnnotationSymbolShape.tsx +31 -31
- package/src/icons/ArrowMarkerIcon.tsx +34 -34
- package/src/icons/ArrowTip.tsx +14 -14
- package/src/icons/ChessPieceIcon.tsx +45 -45
- package/src/icons/SquareMarkerIcon.tsx +20 -20
- package/src/icons/TextMarkerIcon.tsx +29 -29
- package/src/icons/arrow.css +1 -1
- package/src/index.ts +8 -3
- package/src/movetext/Movetext.css +27 -40
- package/src/movetext/Movetext.tsx +163 -228
- package/src/movetext/MovetextImpl.tsx +351 -438
- package/src/movetext/fonts.css +7 -7
- package/src/movetext/htmlFilter.tsx +129 -129
- package/src/movetext/moveFormatter.tsx +37 -37
- package/src/navigationboard/NavigationBoard.tsx +350 -0
- package/src/navigationboard/NavigationButton.ts +72 -0
- package/src/navigationboard/NavigationField.css +36 -0
- package/src/navigationboard/NavigationField.tsx +185 -0
- package/src/navigationboard/NavigationToolbar.css +54 -0
- package/src/navigationboard/NavigationToolbar.tsx +117 -0
- package/src/navigationboard/iconPaths.ts +98 -0
- package/src/sanitization.ts +17 -17
- package/src/types.ts +116 -116
- package/src/util.ts +11 -11
- package/test/01_types.js +167 -167
- package/test/02_chessboard_util.js +114 -114
- package/test/03_error_box_graphic.js +16 -16
- package/test/04_icons_graphic.js +32 -32
- package/test/05_chessboard_graphic.js +60 -58
- package/test/06_chessboard_animation.js +36 -36
- package/test/07_chessboard_interaction.js +101 -101
- package/test/08_chessboard_play_moves.js +62 -62
- package/test/09_chessboard_small_screens.js +42 -21
- package/test/10_movetext_graphic.js +36 -31
- package/test/11_movetext_interaction.js +100 -96
- package/test/12_navigation_board_base.js +151 -0
- package/test/13_navigation_board_graphic.js +68 -0
- package/test/14_navigation_board_autoplay.js +100 -0
- package/test/common/graphic.js +106 -97
- 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_base/controlled/default.png +0 -0
- package/test/graphic_references/12_navigation_board_base/controlled/forbidden_navigation_0.png +0 -0
- package/test/graphic_references/12_navigation_board_base/controlled/forbidden_navigation_1.png +0 -0
- package/test/graphic_references/12_navigation_board_base/controlled/invalid_node_id.png +0 -0
- package/test/graphic_references/12_navigation_board_base/controlled/no_callback_defined_0.png +0 -0
- package/test/graphic_references/12_navigation_board_base/controlled/no_callback_defined_1.png +0 -0
- package/test/graphic_references/12_navigation_board_base/controlled/overriding_initial_node_id.png +0 -0
- package/test/graphic_references/12_navigation_board_base/controlled/regular_navigation_0.png +0 -0
- package/test/graphic_references/12_navigation_board_base/controlled/regular_navigation_1.png +0 -0
- package/test/graphic_references/12_navigation_board_base/controlled/regular_navigation_2.png +0 -0
- package/test/graphic_references/12_navigation_board_base/controlled/regular_navigation_3.png +0 -0
- package/test/graphic_references/12_navigation_board_base/uncontrolled/forbidden_navigation_at_beginning_0.png +0 -0
- package/test/graphic_references/12_navigation_board_base/uncontrolled/forbidden_navigation_at_beginning_1.png +0 -0
- package/test/graphic_references/12_navigation_board_base/uncontrolled/forbidden_navigation_at_beginning_2.png +0 -0
- package/test/graphic_references/12_navigation_board_base/uncontrolled/forbidden_navigation_at_end_0.png +0 -0
- package/test/graphic_references/12_navigation_board_base/uncontrolled/forbidden_navigation_at_end_1.png +0 -0
- package/test/graphic_references/12_navigation_board_base/uncontrolled/forbidden_navigation_at_end_2.png +0 -0
- package/test/graphic_references/12_navigation_board_base/uncontrolled/initial_state_at_end.png +0 -0
- package/test/graphic_references/12_navigation_board_base/uncontrolled/initial_state_at_specific_id.png +0 -0
- package/test/graphic_references/12_navigation_board_base/uncontrolled/initial_state_default.png +0 -0
- package/test/graphic_references/12_navigation_board_base/uncontrolled/initial_state_default_with_game_index.png +0 -0
- package/test/graphic_references/12_navigation_board_base/uncontrolled/initial_state_on_null-move.png +0 -0
- package/test/graphic_references/12_navigation_board_base/uncontrolled/navigation_with_keys_0.png +0 -0
- package/test/graphic_references/12_navigation_board_base/uncontrolled/navigation_with_keys_1.png +0 -0
- package/test/graphic_references/12_navigation_board_base/uncontrolled/navigation_with_keys_2.png +0 -0
- package/test/graphic_references/12_navigation_board_base/uncontrolled/navigation_with_keys_3.png +0 -0
- package/test/graphic_references/12_navigation_board_base/uncontrolled/navigation_with_keys_4.png +0 -0
- package/test/graphic_references/12_navigation_board_base/uncontrolled/regular_flipping_0.png +0 -0
- package/test/graphic_references/12_navigation_board_base/uncontrolled/regular_flipping_1.png +0 -0
- package/test/graphic_references/12_navigation_board_base/uncontrolled/regular_navigation_0.png +0 -0
- package/test/graphic_references/12_navigation_board_base/uncontrolled/regular_navigation_1.png +0 -0
- package/test/graphic_references/12_navigation_board_base/uncontrolled/regular_navigation_2.png +0 -0
- package/test/graphic_references/12_navigation_board_base/uncontrolled/regular_navigation_3.png +0 -0
- package/test/graphic_references/12_navigation_board_base/uncontrolled/regular_navigation_4.png +0 -0
- package/test/graphic_references/12_navigation_board_base/uncontrolled/regular_navigation_5.png +0 -0
- package/test/graphic_references/13_navigation_board_graphic/additional_buttons/error_1.png +0 -0
- package/test/graphic_references/13_navigation_board_graphic/additional_buttons/error_2.png +0 -0
- package/test/graphic_references/13_navigation_board_graphic/additional_buttons/multiple_buttons.png +0 -0
- package/test/graphic_references/13_navigation_board_graphic/additional_buttons/single_button.png +0 -0
- package/test/graphic_references/13_navigation_board_graphic/error/pgn_parsing_error.png +0 -0
- package/test/graphic_references/13_navigation_board_graphic/error/wrong_game_type.png +0 -0
- package/test/graphic_references/13_navigation_board_graphic/theme/custom_1.png +0 -0
- package/test/graphic_references/13_navigation_board_graphic/theme/custom_2.png +0 -0
- package/test/graphic_references/13_navigation_board_graphic/theme/large.png +0 -0
- package/test/graphic_references/13_navigation_board_graphic/theme/small.png +0 -0
- package/test/graphic_references/14_navigation_board_autoplay/controlled/after_1_move_acknowledging_is-playing_changes.png +0 -0
- package/test/graphic_references/14_navigation_board_autoplay/controlled/after_1_move_not_acknowledging_is-playing_changes.png +0 -0
- package/test/graphic_references/14_navigation_board_autoplay/controlled/after_2_moves_acknowledging_node_changes.png +0 -0
- package/test/graphic_references/14_navigation_board_autoplay/controlled/after_2_moves_not_acknowledging_node_changes.png +0 -0
- package/test/graphic_references/14_navigation_board_autoplay/controlled/after_reaching_the_end.png +0 -0
- package/test/graphic_references/14_navigation_board_autoplay/controlled/already_at_the_end.png +0 -0
- package/test/graphic_references/14_navigation_board_autoplay/controlled/initial_state_acknowledging_is-playing_changes.png +0 -0
- package/test/graphic_references/14_navigation_board_autoplay/controlled/initial_state_acknowledging_node_changes.png +0 -0
- package/test/graphic_references/14_navigation_board_autoplay/controlled/initial_state_at_the_end.png +0 -0
- package/test/graphic_references/14_navigation_board_autoplay/controlled/initial_state_close_to_end.png +0 -0
- package/test/graphic_references/14_navigation_board_autoplay/controlled/initial_state_not_acknowledging_is-playing_changes.png +0 -0
- package/test/graphic_references/14_navigation_board_autoplay/controlled/initial_state_not_acknowledging_node_changes.png +0 -0
- package/test/graphic_references/14_navigation_board_autoplay/uncontrolled/after_2_moves_from_beginning_after_stop.png +0 -0
- package/test/graphic_references/14_navigation_board_autoplay/uncontrolled/after_2_moves_from_beginning_before_stop.png +0 -0
- package/test/graphic_references/14_navigation_board_autoplay/uncontrolled/after_reaching_the_end_after_stop.png +0 -0
- package/test/graphic_references/14_navigation_board_autoplay/uncontrolled/after_reaching_the_end_before_stop.png +0 -0
- package/test/graphic_references/14_navigation_board_autoplay/uncontrolled/initial_state_close_to_end.png +0 -0
- package/test/graphic_references/14_navigation_board_autoplay/uncontrolled/initial_state_default.png +0 -0
- package/test/graphic_test_app/03_error_box_graphic/base.tsx +14 -14
- package/test/graphic_test_app/03_error_box_graphic/localization.tsx +1 -1
- package/test/graphic_test_app/04_icons_graphic/chess_piece.tsx +7 -7
- package/test/graphic_test_app/04_icons_graphic/marker.tsx +15 -15
- package/test/graphic_test_app/05_chessboard_graphic/annotations.tsx +7 -7
- package/test/graphic_test_app/05_chessboard_graphic/base.tsx +6 -6
- package/test/graphic_test_app/05_chessboard_graphic/chess_variants.tsx +7 -7
- package/test/graphic_test_app/05_chessboard_graphic/flipped.tsx +5 -5
- package/test/graphic_test_app/05_chessboard_graphic/move.tsx +12 -10
- package/test/graphic_test_app/05_chessboard_graphic/theme.tsx +12 -12
- package/test/graphic_test_app/06_chessboard_animation/base_1.tsx +6 -6
- package/test/graphic_test_app/06_chessboard_animation/base_2.tsx +6 -6
- package/test/graphic_test_app/06_chessboard_animation/base_3.tsx +6 -6
- package/test/graphic_test_app/06_chessboard_animation/on_redraw.tsx +16 -16
- package/test/graphic_test_app/07_chessboard_interaction/click_squares.tsx +5 -5
- package/test/graphic_test_app/07_chessboard_interaction/edit_arrows.tsx +4 -4
- package/test/graphic_test_app/07_chessboard_interaction/error.tsx +2 -2
- package/test/graphic_test_app/07_chessboard_interaction/move_pieces.tsx +5 -5
- package/test/graphic_test_app/08_chessboard_play_moves/base.tsx +8 -8
- package/test/graphic_test_app/08_chessboard_play_moves/promotions.tsx +4 -4
- package/test/graphic_test_app/09_chessboard_small_screens/base.tsx +9 -9
- package/test/graphic_test_app/09_chessboard_small_screens/top_bottom_components.tsx +48 -0
- package/test/graphic_test_app/10_movetext_graphic/base.tsx +4 -4
- package/test/graphic_test_app/10_movetext_graphic/error.tsx +6 -6
- package/test/graphic_test_app/10_movetext_graphic/format_move.tsx +31 -0
- package/test/graphic_test_app/10_movetext_graphic/html.tsx +5 -5
- package/test/graphic_test_app/10_movetext_graphic/options.tsx +10 -9
- package/test/graphic_test_app/11_movetext_interaction/error.tsx +1 -1
- package/test/graphic_test_app/11_movetext_interaction/select_moves.tsx +11 -10
- package/test/graphic_test_app/12_navigation_board_base/controlled.tsx +43 -0
- package/test/graphic_test_app/12_navigation_board_base/uncontrolled.tsx +56 -0
- package/test/graphic_test_app/13_navigation_board_graphic/additional_buttons.tsx +49 -0
- package/test/graphic_test_app/13_navigation_board_graphic/error.tsx +34 -0
- package/test/graphic_test_app/13_navigation_board_graphic/theme.tsx +38 -0
- package/test/graphic_test_app/14_navigation_board_autoplay/controlled.tsx +73 -0
- package/test/graphic_test_app/14_navigation_board_autoplay/uncontrolled.tsx +34 -0
- package/test/graphic_test_app/common/decs.d.ts +2 -2
- package/test/graphic_test_app/common/test_app.css +15 -15
- package/test/graphic_test_app/common/test_app.tsx +48 -48
- package/tsconfig.json +13 -13
|
@@ -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/exception.ts
CHANGED
|
@@ -33,21 +33,21 @@
|
|
|
33
33
|
*/
|
|
34
34
|
export class IllegalArgument {
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
36
|
+
/** Name of the function or component that raises the exception. */
|
|
37
|
+
functionOrComponentName: string;
|
|
38
|
+
|
|
39
|
+
/** Name of the argument that causes the error. */
|
|
40
|
+
argumentName: string;
|
|
41
|
+
|
|
42
|
+
constructor(functionOrComponentName: string, argumentName: string) {
|
|
43
|
+
this.functionOrComponentName = functionOrComponentName;
|
|
44
|
+
this.argumentName = argumentName;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* @ignore
|
|
49
|
+
*/
|
|
50
|
+
toString(): string {
|
|
51
|
+
return `Illegal argument '${this.argumentName}' in function or component ${this.functionOrComponentName}`;
|
|
52
|
+
}
|
|
53
53
|
}
|
package/src/i18n.ts
CHANGED
|
@@ -37,6 +37,14 @@ 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_PLAY_STOP = 'Play/stop the game';
|
|
46
|
+
export let TOOLTIP_FLIP = 'Flip the board';
|
|
47
|
+
|
|
40
48
|
// Movetext
|
|
41
49
|
export let PIECE_SYMBOLS = { 'K':'K', 'Q':'Q', 'R':'R', 'B':'B', 'N':'N', 'P':'P' };
|
|
42
50
|
export let ANNOTATED_BY = 'Annotated by {0}';
|
|
@@ -23,13 +23,13 @@
|
|
|
23
23
|
|
|
24
24
|
|
|
25
25
|
.kokopu-symbolCircle {
|
|
26
|
-
|
|
26
|
+
fill: transparent;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
.kokopu-symbolText {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
30
|
+
font-style: normal;
|
|
31
|
+
font-family: sans-serif;
|
|
32
|
+
text-anchor: middle;
|
|
33
|
+
dominant-baseline: central;
|
|
34
|
+
letter-spacing: 0px;
|
|
35
35
|
}
|
|
@@ -35,30 +35,30 @@ const CIRCLE_RADIUS_FACTOR = 0.425;
|
|
|
35
35
|
|
|
36
36
|
interface AnnotationSymbolShapeProps {
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
38
|
+
/**
|
|
39
|
+
* X-coordinate of the center of the symbol.
|
|
40
|
+
*/
|
|
41
|
+
x: number;
|
|
42
42
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
43
|
+
/**
|
|
44
|
+
* Y-coordinate of the center of the symbol.
|
|
45
|
+
*/
|
|
46
|
+
y: number;
|
|
47
47
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
48
|
+
/**
|
|
49
|
+
* Size of the symbol (i.e. size of square in which the symbol is rendered).
|
|
50
|
+
*/
|
|
51
|
+
size: number;
|
|
52
52
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
53
|
+
/**
|
|
54
|
+
* Symbol code.
|
|
55
|
+
*/
|
|
56
|
+
symbol: AnnotationSymbol;
|
|
57
57
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
58
|
+
/**
|
|
59
|
+
* [CSS color](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value) to use to colorize the shape (for example: `'green'`, `'#ff0000'`...).
|
|
60
|
+
*/
|
|
61
|
+
color: string;
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
|
|
@@ -66,15 +66,15 @@ interface AnnotationSymbolShapeProps {
|
|
|
66
66
|
* Symbol of a text marker.
|
|
67
67
|
*/
|
|
68
68
|
export function AnnotationSymbolShape({ x, y, size, symbol, color }: AnnotationSymbolShapeProps) {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
69
|
+
if (symbol === 'dot') {
|
|
70
|
+
return <circle cx={x} cy={y} r={size * DOT_RADIUS_FACTOR} fill={color} />;
|
|
71
|
+
}
|
|
72
|
+
else if (symbol === 'circle') {
|
|
73
|
+
const thickness = size * SHAPE_THICKNESS_FACTOR;
|
|
74
|
+
return <circle className="kokopu-symbolCircle" cx={x} cy={y} r={size * CIRCLE_RADIUS_FACTOR} stroke={color} strokeWidth={thickness} />;
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
const text = symbol === 'plus' ? '+' : symbol === 'times' ? '\u00d7' : symbol;
|
|
78
|
+
return <text className="kokopu-symbolText" x={x} y={y} fill={color} fontSize={size}>{text}</text>;
|
|
79
|
+
}
|
|
80
80
|
}
|
|
@@ -38,15 +38,15 @@ const ARROW_THICKNESS_FACTOR = 0.2;
|
|
|
38
38
|
|
|
39
39
|
export interface ArrowMarkerIconProps {
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
41
|
+
/**
|
|
42
|
+
* Width and height (in pixels) of the icon.
|
|
43
|
+
*/
|
|
44
|
+
size: number;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* [CSS color](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value) to use to colorize the icon (for example: `'green'`, `'#ff0000'`...).
|
|
48
|
+
*/
|
|
49
|
+
color: string;
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
|
|
@@ -55,29 +55,29 @@ export interface ArrowMarkerIconProps {
|
|
|
55
55
|
*/
|
|
56
56
|
export class ArrowMarkerIcon extends React.Component<ArrowMarkerIconProps> {
|
|
57
57
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
58
|
+
static defaultProps: Partial<ArrowMarkerIconProps> = {
|
|
59
|
+
color: 'currentcolor',
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
private arrowTipId = generateRandomId();
|
|
63
|
+
|
|
64
|
+
render() {
|
|
65
|
+
|
|
66
|
+
// Sanitize the inputs.
|
|
67
|
+
const size = sanitizeBoundedInteger(this.props.size, MIN_SQUARE_SIZE, MAX_SQUARE_SIZE, () => new IllegalArgument('ArrowMarkerIcon', 'size'));
|
|
68
|
+
const color = sanitizeString(this.props.color);
|
|
69
|
+
|
|
70
|
+
// Render the component.
|
|
71
|
+
const halfThickness = size * ARROW_THICKNESS_FACTOR / 2;
|
|
72
|
+
const viewBox = `0 0 ${size} ${size}`;
|
|
73
|
+
return (
|
|
74
|
+
<svg className="kokopu-arrowMarkerIcon" viewBox={viewBox} width={size} height={size}>
|
|
75
|
+
<defs>
|
|
76
|
+
<ArrowTip id={this.arrowTipId} color={this.props.color} />
|
|
77
|
+
</defs>
|
|
78
|
+
<line className="kokopu-arrow" x1={halfThickness} y1={size / 2} x2={size - halfThickness * 3} y2={size / 2} stroke={color}
|
|
79
|
+
strokeWidth={halfThickness * 2} markerEnd={`url(#${this.arrowTipId})`} />
|
|
80
|
+
</svg>
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
83
|
}
|
package/src/icons/ArrowTip.tsx
CHANGED
|
@@ -27,15 +27,15 @@ import * as React from 'react';
|
|
|
27
27
|
|
|
28
28
|
interface ArrowTipProps {
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
30
|
+
/**
|
|
31
|
+
* ID of the element.
|
|
32
|
+
*/
|
|
33
|
+
id: string;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* [CSS color](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value) to use to colorize the shape (for example: `'green'`, `'#ff0000'`...).
|
|
37
|
+
*/
|
|
38
|
+
color: string;
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
|
|
@@ -43,9 +43,9 @@ interface ArrowTipProps {
|
|
|
43
43
|
* Tip of the arrow markers.
|
|
44
44
|
*/
|
|
45
45
|
export function ArrowTip({ id, color }: ArrowTipProps) {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
46
|
+
return (
|
|
47
|
+
<marker id={id} markerWidth={4} markerHeight={4} refX={2.5} refY={2} orient="auto">
|
|
48
|
+
<path fill={color} d="M 4,2 L 0,4 L 1,2 L 0,0 Z" />
|
|
49
|
+
</marker>
|
|
50
|
+
);
|
|
51
51
|
}
|
|
@@ -32,25 +32,25 @@ import { piecesets, DEFAULT_PIECESET } from '../chessboard/piecesets';
|
|
|
32
32
|
|
|
33
33
|
export interface ChessPieceIconProps {
|
|
34
34
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
35
|
+
/**
|
|
36
|
+
* Width and height (in pixels) of each chess piece icon.
|
|
37
|
+
*/
|
|
38
|
+
size: number;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Chess piece(s) to display.
|
|
42
|
+
*/
|
|
43
|
+
type: ChessPieceIconType | ChessPieceIconType[];
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Piece theme ID. Must be a property of `Chessboard.piecesets()`.
|
|
47
|
+
*/
|
|
48
|
+
pieceset: string;
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
|
|
52
52
|
const defaultProps: Partial<ChessPieceIconProps> = {
|
|
53
|
-
|
|
53
|
+
pieceset: DEFAULT_PIECESET,
|
|
54
54
|
};
|
|
55
55
|
|
|
56
56
|
|
|
@@ -59,22 +59,22 @@ const defaultProps: Partial<ChessPieceIconProps> = {
|
|
|
59
59
|
*/
|
|
60
60
|
export function ChessPieceIcon({ size, type, pieceset }: ChessPieceIconProps) {
|
|
61
61
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
62
|
+
// Sanitize the inputs.
|
|
63
|
+
size = sanitizeBoundedInteger(size, MIN_SQUARE_SIZE, MAX_SQUARE_SIZE, () => new IllegalArgument('ChessPieceIcon', 'size'));
|
|
64
|
+
const types = sanitizeChessPieceIconType(type, () => new IllegalArgument('ChessPieceIcon', 'type'));
|
|
65
|
+
const piecesetData = piecesets[pieceset];
|
|
66
|
+
if (!piecesetData) {
|
|
67
|
+
throw new IllegalArgument('ChessPieceIcon', 'pieceset');
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Render the component.
|
|
71
|
+
const width = size * types.length;
|
|
72
|
+
const viewBox = `0 0 ${width} ${size}`;
|
|
73
|
+
return (
|
|
74
|
+
<svg className="kokopu-chessPieceIcon" viewBox={viewBox} width={width} height={size}>
|
|
75
|
+
{types.map((t, i) => <image key={i} x={i * size} y={0} width={size} height={size} href={piecesetData[t]} />)}
|
|
76
|
+
</svg>
|
|
77
|
+
);
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
ChessPieceIcon.defaultProps = defaultProps;
|
|
@@ -84,18 +84,18 @@ ChessPieceIcon.defaultProps = defaultProps;
|
|
|
84
84
|
* Sanitization method for the small-screen limits parameter.
|
|
85
85
|
*/
|
|
86
86
|
function sanitizeChessPieceIconType(type: ChessPieceIconType | ChessPieceIconType[], exceptionBuilder: () => IllegalArgument): ChessPieceIconType[] {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
87
|
+
if (Array.isArray(type)) {
|
|
88
|
+
return type.map(t => {
|
|
89
|
+
if (!isChessPieceIconType(t)) {
|
|
90
|
+
throw exceptionBuilder();
|
|
91
|
+
}
|
|
92
|
+
return t;
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
else if (isChessPieceIconType(type)) {
|
|
96
|
+
return [ type ];
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
throw exceptionBuilder();
|
|
100
|
+
}
|
|
101
101
|
}
|
|
@@ -33,20 +33,20 @@ const SQUARE_MARGIN_FACTOR = 0.1;
|
|
|
33
33
|
|
|
34
34
|
export interface SquareMarkerIconProps {
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
36
|
+
/**
|
|
37
|
+
* Width and height (in pixels) of the icon.
|
|
38
|
+
*/
|
|
39
|
+
size: number;
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
/**
|
|
42
|
+
* [CSS color](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value) to use to colorize the icon (for example: `'green'`, `'#ff0000'`...).
|
|
43
|
+
*/
|
|
44
|
+
color: string;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
|
|
48
48
|
const defaultProps: Partial<SquareMarkerIconProps> = {
|
|
49
|
-
|
|
49
|
+
color: 'currentcolor',
|
|
50
50
|
};
|
|
51
51
|
|
|
52
52
|
|
|
@@ -55,18 +55,18 @@ const defaultProps: Partial<SquareMarkerIconProps> = {
|
|
|
55
55
|
*/
|
|
56
56
|
export function SquareMarkerIcon({ size, color }: SquareMarkerIconProps) {
|
|
57
57
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
58
|
+
// Sanitize the inputs.
|
|
59
|
+
size = sanitizeBoundedInteger(size, MIN_SQUARE_SIZE, MAX_SQUARE_SIZE, () => new IllegalArgument('SquareMarkerIcon', 'size'));
|
|
60
|
+
color = sanitizeString(color);
|
|
61
61
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
62
|
+
// Render the component.
|
|
63
|
+
const margin = Math.round(size * SQUARE_MARGIN_FACTOR);
|
|
64
|
+
const viewBox = `0 0 ${size} ${size}`;
|
|
65
|
+
return (
|
|
66
|
+
<svg className="kokopu-squareMarkerIcon" viewBox={viewBox} width={size} height={size}>
|
|
67
|
+
<rect x={margin} y={margin} width={size - margin * 2} height={size - margin * 2} fill={color} />
|
|
68
|
+
</svg>
|
|
69
|
+
);
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
SquareMarkerIcon.defaultProps = defaultProps;
|