kokopu-react 1.7.2 → 1.8.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 CHANGED
@@ -1,6 +1,16 @@
1
1
  ChangeLog
2
2
  =========
3
3
 
4
+ 1.8.0 (August 26, 2022)
5
+ -----------------------
6
+ * Upgrade Kokopu to Kokopu 3.0.
7
+ * Upgrade dependencies.
8
+
9
+ 1.7.2 (August 3, 2022)
10
+ ----------------------
11
+ * Fix URLs in documentation.
12
+ * Upgrade dependencies.
13
+
4
14
  1.7.1 (June 23, 2022)
5
15
  ---------------------
6
16
  * `React` and `kokopu` declared as peer dependencies.
@@ -13,7 +13,7 @@ var _reactDraggable = _interopRequireDefault(require("react-draggable"));
13
13
 
14
14
  var _reactMotion = require("react-motion");
15
15
 
16
- var _kokopu = _interopRequireDefault(require("kokopu"));
16
+ var _kokopu = require("kokopu");
17
17
 
18
18
  var _colorsets2 = _interopRequireDefault(require("./impl/colorsets"));
19
19
 
@@ -161,12 +161,10 @@ var Chessboard = /*#__PURE__*/function (_React$Component) {
161
161
 
162
162
 
163
163
  var squares = [];
164
-
165
- _kokopu["default"].forEachSquare(function (sq) {
164
+ (0, _kokopu.forEachSquare)(function (sq) {
166
165
  return squares.push(_this2.renderSquare(squareSize, colorset, sq));
167
166
  }); // Render coordinates.
168
167
 
169
-
170
168
  var rankCoordinates = [];
171
169
  var fileCoordinates = [];
172
170
 
@@ -221,12 +219,10 @@ var Chessboard = /*#__PURE__*/function (_React$Component) {
221
219
  var _this4 = this;
222
220
 
223
221
  var pieces = [];
224
-
225
- _kokopu["default"].forEachSquare(function (sq) {
222
+ (0, _kokopu.forEachSquare)(function (sq) {
226
223
  return pieces.push(_this4.renderPieceAnimated(positionBefore, move, alpha, squareSize, pieceset, sq));
227
224
  });
228
-
229
- return /*#__PURE__*/_react["default"].createElement(_react["default"].Fragment, null, pieces, this.renderMoveArrow(move, alpha, squareSize, colorset), this.renderTurnFlag(_kokopu["default"].oppositeColor(positionBefore.turn()), squareSize, pieceset));
225
+ return /*#__PURE__*/_react["default"].createElement(_react["default"].Fragment, null, pieces, this.renderMoveArrow(move, alpha, squareSize, colorset), this.renderTurnFlag((0, _kokopu.oppositeColor)(positionBefore.turn()), squareSize, pieceset));
230
226
  }
231
227
  /**
232
228
  * Render the board content when the animation has been completed (or if there is no animation).
@@ -246,15 +242,13 @@ var Chessboard = /*#__PURE__*/function (_React$Component) {
246
242
 
247
243
  var pieces = [];
248
244
  var handles = [];
249
-
250
- _kokopu["default"].forEachSquare(function (sq) {
245
+ (0, _kokopu.forEachSquare)(function (sq) {
251
246
  pieces.push(_this5.renderPiece(position, squareSize, pieceset, sq));
252
247
 
253
248
  if (_this5.props.interactionMode) {
254
249
  handles.push(_this5.renderSquareHandle(position, squareSize, sq));
255
250
  }
256
251
  });
257
-
258
252
  return /*#__PURE__*/_react["default"].createElement(_react["default"].Fragment, null, this.renderSquareMarkers(sqm, squareSize, colorset), this.renderHoveredSquare(squareSize, colorset), pieces, this.renderTextMarkers(txtm, squareSize, colorset), this.renderArrowMarkers(arm, squareSize, colorset), this.renderMoveArrow(move, 1, squareSize, colorset), handles, this.renderPromotionDrawer(position, squareSize, colorset, pieceset), this.renderDraggedPiece(position, squareSize, pieceset), this.renderDraggedArrow(squareSize, colorset), this.renderTurnFlag(position.turn(), squareSize, pieceset));
259
253
  }
260
254
  }, {
@@ -270,7 +264,7 @@ var Chessboard = /*#__PURE__*/function (_React$Component) {
270
264
  y: y,
271
265
  width: squareSize,
272
266
  height: squareSize,
273
- fill: colorset[_kokopu["default"].squareColor(sq)]
267
+ fill: colorset[(0, _kokopu.squareColor)(sq)]
274
268
  });
275
269
  }
276
270
  }, {
@@ -905,9 +899,9 @@ var Chessboard = /*#__PURE__*/function (_React$Component) {
905
899
  }, {
906
900
  key: "getSquareCoordinates",
907
901
  value: function getSquareCoordinates(squareSize, sq) {
908
- var _kokopu$squareToCoord = _kokopu["default"].squareToCoordinates(sq),
909
- file = _kokopu$squareToCoord.file,
910
- rank = _kokopu$squareToCoord.rank;
902
+ var _squareToCoordinates = (0, _kokopu.squareToCoordinates)(sq),
903
+ file = _squareToCoordinates.file,
904
+ rank = _squareToCoordinates.rank;
911
905
 
912
906
  var x = this.props.flipped ? (7 - file) * squareSize : file * squareSize;
913
907
  var y = this.props.flipped ? rank * squareSize : (7 - rank) * squareSize;
@@ -956,7 +950,7 @@ var Chessboard = /*#__PURE__*/function (_React$Component) {
956
950
  } // Compute the position after the move and return the result.
957
951
 
958
952
 
959
- var positionAfter = new _kokopu["default"].Position(positionInfo.position);
953
+ var positionAfter = new _kokopu.Position(positionInfo.position);
960
954
  positionAfter.play(moveInfo.move);
961
955
  return {
962
956
  positionError: false,
@@ -975,7 +969,7 @@ var Chessboard = /*#__PURE__*/function (_React$Component) {
975
969
  value: function getSquareAt(squareSize, x, y) {
976
970
  var file = this.props.flipped ? 7 - Math.floor(x / squareSize) : Math.floor(x / squareSize);
977
971
  var rank = this.props.flipped ? Math.floor(y / squareSize) : 7 - Math.floor(y / squareSize);
978
- return file >= 0 && file < 8 && rank >= 0 && rank < 8 ? _kokopu["default"].coordinatesToSquare(file, rank) : '-';
972
+ return file >= 0 && file < 8 && rank >= 0 && rank < 8 ? (0, _kokopu.coordinatesToSquare)(file, rank) : '-';
979
973
  }
980
974
  /**
981
975
  * Return the DOM ID of an arrow tip with the given color.
@@ -1146,26 +1140,22 @@ var Chessboard = /*#__PURE__*/function (_React$Component) {
1146
1140
  exports["default"] = Chessboard;
1147
1141
  Chessboard.propTypes = {
1148
1142
  /**
1149
- * Displayed position. Can be a [kokopu.Position](https://kokopu.yo35.org/docs/current/Position.html) object,
1143
+ * Displayed position. Can be a [kokopu.Position](https://kokopu.yo35.org/docs/current/classes/Position.html) object,
1150
1144
  * a [FEN string](https://en.wikipedia.org/wiki/Forsyth%E2%80%93Edwards_Notation),
1151
1145
  * `'start'` (usual starting position), or `'empty'` (empty board).
1152
1146
  *
1153
1147
  * Optionally, the FEN string can be prefixed with `'variant:'`, `variant` corresponding to one of the
1154
- * [game variant](https://kokopu.yo35.org/docs/current/global.html#GameVariant) supported by Kokopu. For instance:
1148
+ * [game variant](https://kokopu.yo35.org/docs/current/types/GameVariant.html) supported by Kokopu. For instance:
1155
1149
  * `'chess960:nrkbqrbn/pppppppp/8/8/8/8/PPPPPPPP/NRKBQRBN w KQkq - 0 1'`.
1156
1150
  */
1157
- position: _propTypes["default"].oneOfType([_propTypes["default"].instanceOf(_kokopu["default"].Position), _propTypes["default"].string]),
1151
+ position: _propTypes["default"].oneOfType([_propTypes["default"].instanceOf(_kokopu.Position), _propTypes["default"].string]),
1158
1152
 
1159
1153
  /**
1160
- * Displayed move (optional), defined either as a [kokopu.MoveDescriptor](https://kokopu.yo35.org/docs/current/MoveDescriptor.html) object
1154
+ * Displayed move (optional), defined either as a [kokopu.MoveDescriptor](https://kokopu.yo35.org/docs/current/classes/MoveDescriptor.html) object
1161
1155
  * or as a [SAN string](https://en.wikipedia.org/wiki/Algebraic_notation_(chess)) (e.g. `'Nf3'`). In both cases, it must represent
1162
1156
  * a legal move in position defined in attribute `position`.
1163
1157
  */
1164
- move: _propTypes["default"].oneOfType([function (props, propName, componentName) {
1165
- if (!_kokopu["default"].isMoveDescriptor(props[propName])) {
1166
- return new Error("Invalid prop ".concat(propName, " supplied to ").concat(componentName, ". Validation failed."));
1167
- }
1168
- }, _propTypes["default"].string]),
1158
+ move: _propTypes["default"].oneOfType([_propTypes["default"].instanceOf(_kokopu.MoveDescriptor), _propTypes["default"].string]),
1169
1159
 
1170
1160
  /**
1171
1161
  * Square markers, defined as a "square -> color" struct (e.g. `{ e4: 'g', d5: 'r' }`) or as a comma-separated CSL string (e.g. `'Rd5,Ge4'`).
@@ -1332,7 +1322,7 @@ function computeCoordinateFontSize(squareSize) {
1332
1322
 
1333
1323
 
1334
1324
  function parsePosition(position) {
1335
- if (position instanceof _kokopu["default"].Position) {
1325
+ if (position instanceof _kokopu.Position) {
1336
1326
  return {
1337
1327
  error: false,
1338
1328
  position: position
@@ -1341,11 +1331,11 @@ function parsePosition(position) {
1341
1331
  try {
1342
1332
  return {
1343
1333
  error: false,
1344
- position: new _kokopu["default"].Position(position)
1334
+ position: new _kokopu.Position(position)
1345
1335
  };
1346
1336
  } catch (e) {
1347
1337
  // istanbul ignore else
1348
- if (e instanceof _kokopu["default"].exception.InvalidFEN) {
1338
+ if (e instanceof _kokopu.exception.InvalidFEN) {
1349
1339
  return {
1350
1340
  error: true,
1351
1341
  message: e.message
@@ -1367,7 +1357,7 @@ function parsePosition(position) {
1367
1357
 
1368
1358
 
1369
1359
  function parseMove(position, move) {
1370
- if (_kokopu["default"].isMoveDescriptor(move)) {
1360
+ if (move instanceof _kokopu.MoveDescriptor) {
1371
1361
  return {
1372
1362
  error: false,
1373
1363
  move: move
@@ -1380,7 +1370,7 @@ function parseMove(position, move) {
1380
1370
  };
1381
1371
  } catch (e) {
1382
1372
  // istanbul ignore else
1383
- if (e instanceof _kokopu["default"].exception.InvalidNotation) {
1373
+ if (e instanceof _kokopu.exception.InvalidNotation) {
1384
1374
  return {
1385
1375
  error: true,
1386
1376
  message: e.message
@@ -11,6 +11,8 @@ var _react = _interopRequireDefault(require("react"));
11
11
 
12
12
  var _i18n = _interopRequireDefault(require("./i18n"));
13
13
 
14
+ var _util = require("./impl/util");
15
+
14
16
  require("./css/error_box.css");
15
17
 
16
18
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
@@ -133,7 +135,7 @@ function ellipsisAt(text, pos, backwardCharacters, forwardCharacters, lineNumber
133
135
  var secondLine = Array(1 + e1.length + pos - p1).join(' ') + '^';
134
136
 
135
137
  if (lineNumber) {
136
- secondLine += ' (' + _i18n["default"].LINE.replace(/\{0\}/g, lineNumber) + ')';
138
+ secondLine += " (".concat((0, _util.fillPlaceholder)(_i18n["default"].LINE, lineNumber), ")");
137
139
  }
138
140
 
139
141
  return excerpt + '\n' + secondLine;
@@ -11,10 +11,12 @@ var _propTypes = _interopRequireDefault(require("prop-types"));
11
11
 
12
12
  var _react = _interopRequireDefault(require("react"));
13
13
 
14
- var _kokopu = _interopRequireDefault(require("kokopu"));
14
+ var _kokopu = require("kokopu");
15
15
 
16
16
  var _HtmlSanitizer = _interopRequireDefault(require("./impl/HtmlSanitizer"));
17
17
 
18
+ var _util = require("./impl/util");
19
+
18
20
  var _Chessboard = _interopRequireDefault(require("./Chessboard"));
19
21
 
20
22
  var _ErrorBox = _interopRequireDefault(require("./ErrorBox"));
@@ -147,7 +149,7 @@ var Movetext = /*#__PURE__*/function (_React$Component) {
147
149
  }, sanitizeHtml(title));
148
150
  var ratingElement = rating === undefined ? undefined : /*#__PURE__*/_react["default"].createElement("span", {
149
151
  className: "kokopu-header-playerRating"
150
- }, sanitizeHtml(rating));
152
+ }, rating);
151
153
  var separator = title === undefined || rating === undefined ? undefined : "\xA0"; // \u00a0 == &nbsp;
152
154
 
153
155
  var titleRatingGroup = title === undefined && rating === undefined ? undefined : /*#__PURE__*/_react["default"].createElement("span", {
@@ -225,7 +227,7 @@ var Movetext = /*#__PURE__*/function (_React$Component) {
225
227
  return undefined;
226
228
  }
227
229
 
228
- annotator = _i18n["default"].ANNOTATED_BY.replace(/\{0\}/g, annotator);
230
+ annotator = (0, _util.fillPlaceholder)(_i18n["default"].ANNOTATED_BY, annotator);
229
231
  return /*#__PURE__*/_react["default"].createElement("div", {
230
232
  className: "kokopu-header-annotator",
231
233
  key: "annotator"
@@ -405,7 +407,7 @@ var Movetext = /*#__PURE__*/function (_React$Component) {
405
407
  return /*#__PURE__*/_react["default"].createElement("span", {
406
408
  className: "kokopu-nag",
407
409
  key: nag
408
- }, _kokopu["default"].nagSymbol(nag));
410
+ }, (0, _kokopu.nagSymbol)(nag));
409
411
  }); // Class
410
412
 
411
413
  var nodeId = node.id();
@@ -706,14 +708,14 @@ var Movetext = /*#__PURE__*/function (_React$Component) {
706
708
  exports["default"] = Movetext;
707
709
  Movetext.propTypes = {
708
710
  /**
709
- * Displayed position. Can be a [kokopu.Game](https://kokopu.yo35.org/docs/current/Game.html) object,
710
- * a [kokopu.Database](https://kokopu.yo35.org/docs/current/Database.html) object,
711
+ * Displayed position. Can be a [kokopu.Game](https://kokopu.yo35.org/docs/current/classes/Game.html) object,
712
+ * a [kokopu.Database](https://kokopu.yo35.org/docs/current/classes/Database.html) object,
711
713
  * or a [PGN string](https://en.wikipedia.org/wiki/Portable_Game_Notation).
712
714
  */
713
- game: _propTypes["default"].oneOfType([_propTypes["default"].instanceOf(_kokopu["default"].Game), _propTypes["default"].instanceOf(_kokopu["default"].Database), _propTypes["default"].string]),
715
+ game: _propTypes["default"].oneOfType([_propTypes["default"].instanceOf(_kokopu.Game), _propTypes["default"].instanceOf(_kokopu.Database), _propTypes["default"].string]),
714
716
 
715
717
  /**
716
- * Index of the game to display (only if attribute `game` is a [kokopu.Database](https://kokopu.yo35.org/docs/current/Database.html)
718
+ * Index of the game to display (only if attribute `game` is a [kokopu.Database](https://kokopu.yo35.org/docs/current/classes/Database.html)
717
719
  * or a [PGN string](https://en.wikipedia.org/wiki/Portable_Game_Notation)): `0` for the first game of the database/PGN, `1` for the second one, etc.
718
720
  * If omitted, the first game of the database/PGN is displayed.
719
721
  */
@@ -759,7 +761,7 @@ Movetext.propTypes = {
759
761
 
760
762
  /**
761
763
  * ID of the selected move (or `'start'` for the beginning of the main variation).
762
- * Use [kokopu.Node#id](https://kokopu.yo35.org/docs/current/Node.html#id) to get the ID of a game move.
764
+ * Use [kokopu.Node#id](https://kokopu.yo35.org/docs/current/classes/Node.html#id) to get the ID of a game move.
763
765
  */
764
766
  selection: _propTypes["default"].string,
765
767
 
@@ -773,7 +775,7 @@ Movetext.propTypes = {
773
775
  /**
774
776
  * Callback invoked when the user selects a move (only if `interactionMode` is set to `'selectMove'`).
775
777
  *
776
- * @param {string?} nodeId ID of the selected move (as returned by [kokopu.Node#id](https://kokopu.yo35.org/docs/current/Node.html#id)),
778
+ * @param {string?} nodeId ID of the selected move (as returned by [kokopu.Node#id](https://kokopu.yo35.org/docs/current/classes/Node.html#id)),
777
779
  * `'start'` for the beginning of the main variation, or `undefined` if the user unselects the previously selected move.
778
780
  * @param {string} evtOrigin Origin of the event. Can be:
779
781
  * - `'key-first'`: the event has been triggered by the "go-to-first-move" key (aka. the home key),
@@ -785,7 +787,7 @@ Movetext.propTypes = {
785
787
  onMoveSelected: _propTypes["default"].func
786
788
  };
787
789
  Movetext.defaultProps = {
788
- game: new _kokopu["default"].Game(),
790
+ game: new _kokopu.Game(),
789
791
  gameIndex: 0,
790
792
  diagramOptions: {},
791
793
  pieceSymbols: 'native',
@@ -863,21 +865,28 @@ function sanitizeHtml(text, sanitizer) {
863
865
 
864
866
 
865
867
  function parseGame(game, gameIndex) {
866
- if (game instanceof _kokopu["default"].Game) {
868
+ if (game instanceof _kokopu.Game) {
867
869
  return {
868
870
  error: false,
869
871
  game: game
870
872
  };
871
- } else if (game instanceof _kokopu["default"].Database || typeof game === 'string') {
873
+ } else if (game instanceof _kokopu.Database || typeof game === 'string') {
874
+ if (!Number.isInteger(gameIndex) || gameIndex < 0) {
875
+ return {
876
+ error: true,
877
+ message: _i18n["default"].INVALID_GAME_INDEX_ATTRIBUTE_ERROR_MESSAGE
878
+ };
879
+ }
880
+
872
881
  try {
873
- var result = game instanceof _kokopu["default"].Database ? game.game(gameIndex) : _kokopu["default"].pgnRead(game, gameIndex);
882
+ var result = game instanceof _kokopu.Database ? game.game(gameIndex) : (0, _kokopu.pgnRead)(game, gameIndex);
874
883
  return {
875
884
  error: false,
876
885
  game: result
877
886
  };
878
887
  } catch (e) {
879
888
  // istanbul ignore else
880
- if (e instanceof _kokopu["default"].exception.InvalidPGN) {
889
+ if (e instanceof _kokopu.exception.InvalidPGN) {
881
890
  return {
882
891
  error: true,
883
892
  message: e.message,
package/dist/lib/i18n.js CHANGED
@@ -44,7 +44,8 @@ var i18n = {
44
44
  },
45
45
  ANNOTATED_BY: 'Annotated by {0}',
46
46
  INVALID_PGN_ERROR_TITLE: 'Invalid PGN string.',
47
- INVALID_GAME_ATTRIBUTE_ERROR_MESSAGE: 'Invalid "game" attribute.'
47
+ INVALID_GAME_ATTRIBUTE_ERROR_MESSAGE: 'Invalid "game" attribute.',
48
+ INVALID_GAME_INDEX_ATTRIBUTE_ERROR_MESSAGE: 'Invalid "game index" attribute.'
48
49
  };
49
50
  var _default = i18n;
50
51
  exports["default"] = _default;
@@ -4,6 +4,7 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.MIN_SQUARE_SIZE = exports.MAX_SQUARE_SIZE = void 0;
7
+ exports.fillPlaceholder = fillPlaceholder;
7
8
  exports.generateRandomId = generateRandomId;
8
9
  exports.isValidColor = isValidColor;
9
10
  exports.isValidSquare = isValidSquare;
@@ -48,6 +49,17 @@ function generateRandomId() {
48
49
  return result;
49
50
  }
50
51
 
52
+ function fillPlaceholder(message) {
53
+ for (var _len = arguments.length, placeholderValues = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
54
+ placeholderValues[_key - 1] = arguments[_key];
55
+ }
56
+
57
+ return message.replace(/{(\d+)}/g, function (match, placeholder) {
58
+ var placeholderIndex = Number(placeholder);
59
+ return placeholderIndex < placeholderValues.length ? placeholderValues[placeholderIndex] : match;
60
+ });
61
+ }
62
+
51
63
  function sanitizeInteger(input, min, max) {
52
64
  return Math.min(Math.max(Math.round(input), min), max);
53
65
  }
@@ -21,7 +21,7 @@
21
21
 
22
22
 
23
23
  import React from 'react';
24
- import kokopu from 'kokopu';
24
+ import { Position, oppositeColor } from 'kokopu';
25
25
 
26
26
  import { Chessboard, SquareMarkerIcon, TextMarkerIcon, ArrowMarkerIcon, flattenSquareMarkers, flattenTextMarkers, flattenArrowMarkers } from '../../src/index';
27
27
  import { buildComponentDemoCode } from './util';
@@ -53,7 +53,7 @@ export default class Page extends React.Component {
53
53
  constructor(props) {
54
54
  super(props);
55
55
  this.state = {
56
- position: new kokopu.Position(),
56
+ position: new Position(),
57
57
  flipped: false,
58
58
  interactionMode: 'movePieces',
59
59
  pieceEditMode: 'wp',
@@ -83,12 +83,12 @@ export default class Page extends React.Component {
83
83
  <FormControlLabel label="Flip"
84
84
  control={<Switch checked={this.state.flipped} onChange={() => this.set('flipped', !this.state.flipped)} color="primary" />}
85
85
  />
86
- <Button color="primary" size="small" variant="contained" onClick={() => this.handleTurnClicked(kokopu.oppositeColor(this.state.position.turn()))}>
86
+ <Button color="primary" size="small" variant="contained" onClick={() => this.handleTurnClicked(oppositeColor(this.state.position.turn()))}>
87
87
  Change turn
88
88
  </Button>
89
89
  <ButtonGroup color="primary" size="small">
90
- <Button onClick={() => this.set('position', new kokopu.Position('empty'))}>Clear</Button>
91
- <Button onClick={() => this.set('position', new kokopu.Position())}>Reset</Button>
90
+ <Button onClick={() => this.set('position', new Position('empty'))}>Clear</Button>
91
+ <Button onClick={() => this.set('position', new Position())}>Reset</Button>
92
92
  </ButtonGroup>
93
93
  </Stack>
94
94
  <Box>
@@ -266,20 +266,20 @@ export default class Page extends React.Component {
266
266
  }
267
267
 
268
268
  handleTurnClicked(newTurn) {
269
- let newPosition = new kokopu.Position(this.state.position);
269
+ let newPosition = new Position(this.state.position);
270
270
  newPosition.turn(newTurn);
271
271
  this.set('position', newPosition);
272
272
  }
273
273
 
274
274
  handlePieceMoved(from, to) {
275
- let newPosition = new kokopu.Position(this.state.position);
275
+ let newPosition = new Position(this.state.position);
276
276
  newPosition.square(to, newPosition.square(from));
277
277
  newPosition.square(from, '-');
278
278
  this.set('position', newPosition);
279
279
  }
280
280
 
281
281
  handleMovePlayed(move) {
282
- let newPosition = new kokopu.Position(this.state.position);
282
+ let newPosition = new Position(this.state.position);
283
283
  newPosition.play(move);
284
284
  this.set('position', newPosition);
285
285
  }
@@ -318,7 +318,7 @@ export default class Page extends React.Component {
318
318
  this.set('textMarkers', newTextMarkers);
319
319
  }
320
320
  else if (this.state.interactionMode === 'addRemovePieces') {
321
- let newPosition = new kokopu.Position(this.state.position);
321
+ let newPosition = new Position(this.state.position);
322
322
  newPosition.square(sq, newPosition.square(sq) === this.state.pieceEditMode ? '-' : this.state.pieceEditMode);
323
323
  this.set('position', newPosition);
324
324
  }
@@ -21,7 +21,7 @@
21
21
 
22
22
 
23
23
  import React from 'react';
24
- import kokopu from 'kokopu';
24
+ import { exception, Position } from 'kokopu';
25
25
 
26
26
  import { Chessboard, ArrowMarkerIcon } from '../../src/index';
27
27
  import { buildComponentDemoCode } from './util';
@@ -45,8 +45,8 @@ export default class Page extends React.Component {
45
45
 
46
46
  constructor(props) {
47
47
  super(props);
48
- let position = new kokopu.Position();
49
- let positionAfter = new kokopu.Position(position);
48
+ let position = new Position();
49
+ let positionAfter = new Position(position);
50
50
  positionAfter.play('e4');
51
51
  this.state = {
52
52
  position: position,
@@ -88,8 +88,8 @@ export default class Page extends React.Component {
88
88
  <TextField label="Move" variant="standard" value={this.state.editedMove} onChange={evt => this.set('editedMove', evt.target.value)} />
89
89
  <Button color="primary" size="small" variant="contained" onClick={() => this.handlePlayClicked()}>Play</Button>
90
90
  <ButtonGroup color="primary" size="small">
91
- <Button onClick={() => this.setPosition(new kokopu.Position('empty'))}>Clear</Button>
92
- <Button onClick={() => this.setPosition(new kokopu.Position())}>Reset</Button>
91
+ <Button onClick={() => this.setPosition(new Position('empty'))}>Clear</Button>
92
+ <Button onClick={() => this.setPosition(new Position())}>Reset</Button>
93
93
  </ButtonGroup>
94
94
  </Stack>
95
95
  </>);
@@ -164,7 +164,7 @@ export default class Page extends React.Component {
164
164
 
165
165
  handlePlayClicked() {
166
166
  let newState = {};
167
- let currentPosition = new kokopu.Position(this.state.positionAfter ? this.state.positionAfter : this.state.position);
167
+ let currentPosition = new Position(this.state.positionAfter ? this.state.positionAfter : this.state.position);
168
168
  let move = this.state.editedMove.trim();
169
169
  if (move === '') {
170
170
  newState.position = currentPosition;
@@ -176,11 +176,11 @@ export default class Page extends React.Component {
176
176
  let moveDescriptor = currentPosition.notation(move);
177
177
  newState.position = currentPosition;
178
178
  newState.playedMove = currentPosition.notation(moveDescriptor);
179
- newState.positionAfter = new kokopu.Position(currentPosition);
179
+ newState.positionAfter = new Position(currentPosition);
180
180
  newState.positionAfter.play(moveDescriptor);
181
181
  }
182
182
  catch (e) {
183
- if (e instanceof kokopu.exception.InvalidNotation) {
183
+ if (e instanceof exception.InvalidNotation) {
184
184
  newState.position = currentPosition;
185
185
  newState.playedMove = move;
186
186
  newState.positionAfter = null;
@@ -21,7 +21,7 @@
21
21
 
22
22
 
23
23
  import React from 'react';
24
- import kokopu from 'kokopu';
24
+ import { pgnRead } from 'kokopu';
25
25
 
26
26
  import { Chessboard, Movetext } from '../../src/index';
27
27
  import { buildComponentDemoCode } from './util';
@@ -143,7 +143,7 @@ export default class Page extends React.Component {
143
143
  }
144
144
 
145
145
  getCurrentPositionAndAnnotations() {
146
- let game = kokopu.pgnRead(this.state.pgn, 0);
146
+ let game = pgnRead(this.state.pgn, 0);
147
147
  if (this.state.selection === 'start') {
148
148
  let mainVariation = game.mainVariation();
149
149
  return { position: mainVariation.initialPosition(), csl: mainVariation.tag('csl'), cal: mainVariation.tag('cal') };
@@ -21,7 +21,7 @@
21
21
 
22
22
 
23
23
  import React from 'react';
24
- import kokopu from 'kokopu';
24
+ import { Position } from 'kokopu';
25
25
  import testApp from './common/test_app';
26
26
  import { Chessboard } from '../src/index';
27
27
 
@@ -30,6 +30,6 @@ testApp([ /* eslint-disable react/jsx-key */
30
30
  <Chessboard position="empty" />,
31
31
  <Chessboard position="something invalid" />,
32
32
  <Chessboard position="r1bqkbnr/pppp1ppp/2n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R b KQkq - 3 3" />,
33
- <Chessboard position={new kokopu.Position('8/8/1r6/8/5k1K/8/8/8 b - - 0 1')} />,
33
+ <Chessboard position={new Position('8/8/1r6/8/5k1K/8/8/8 b - - 0 1')} />,
34
34
  <Chessboard position={42} />,
35
35
  ]); /* eslint-enable react/jsx-key */
@@ -21,7 +21,7 @@
21
21
 
22
22
 
23
23
  import React from 'react';
24
- import kokopu from 'kokopu';
24
+ import { Position } from 'kokopu';
25
25
  import testApp from './common/test_app';
26
26
  import { Chessboard } from '../src/index';
27
27
 
@@ -30,5 +30,5 @@ testApp([ /* eslint-disable react/jsx-key */
30
30
  <Chessboard flipped={true} position="empty" />,
31
31
  <Chessboard flipped={true} position="something invalid" />,
32
32
  <Chessboard flipped={true} position="r1bqkbnr/pppp1ppp/2n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R b KQkq - 3 3" />,
33
- <Chessboard flipped={true} position={new kokopu.Position('8/8/1r6/8/5k1K/8/8/8 b - - 0 1')} />,
33
+ <Chessboard flipped={true} position={new Position('8/8/1r6/8/5k1K/8/8/8 b - - 0 1')} />,
34
34
  ]); /* eslint-enable react/jsx-key */
@@ -21,11 +21,11 @@
21
21
 
22
22
 
23
23
  import React from 'react';
24
- import kokopu from 'kokopu';
24
+ import { Position } from 'kokopu';
25
25
  import testApp from './common/test_app';
26
26
  import { Chessboard } from '../src/index';
27
27
 
28
- let pos = new kokopu.Position('r1bqkbnr/1ppp1ppp/p1n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R w KQkq - 0 4');
28
+ let pos = new Position('r1bqkbnr/1ppp1ppp/p1n5/1B2p3/4P3/5N2/PPPP1PPP/RNBQK2R w KQkq - 0 4');
29
29
  let move = pos.notation('Bxc6');
30
30
 
31
31
  testApp([ /* eslint-disable react/jsx-key */
@@ -21,17 +21,17 @@
21
21
 
22
22
 
23
23
  import React from 'react';
24
- import kokopu from 'kokopu';
24
+ import { Game, pgnRead } from 'kokopu';
25
25
  import testApp from './common/test_app';
26
26
  import { Movetext } from '../src/index';
27
27
 
28
28
  import pgn from './common/games.pgn';
29
29
 
30
- let game = new kokopu.Game();
30
+ let game = new Game();
31
31
  game.mainVariation().play('e4').play('e5').play('Bc4').play('Nc6').play('Qh5').play('Nf6').play('Qxf7#');
32
32
  game.result('1-0');
33
33
 
34
- let database = kokopu.pgnRead(pgn);
34
+ let database = pgnRead(pgn);
35
35
 
36
36
  testApp([ /* eslint-disable react/jsx-key */
37
37
  <Movetext game={game} />,
@@ -21,18 +21,19 @@
21
21
 
22
22
 
23
23
  import React from 'react';
24
- import kokopu from 'kokopu';
24
+ import { pgnRead } from 'kokopu';
25
25
  import testApp from './common/test_app';
26
26
  import { Movetext } from '../src/index';
27
27
 
28
28
  import pgn from './common/games.pgn';
29
29
  import dummyPgn from './common/dummy.pgn';
30
30
 
31
- let database = kokopu.pgnRead(pgn);
31
+ let database = pgnRead(pgn);
32
32
 
33
33
  testApp([ /* eslint-disable react/jsx-key */
34
+ <Movetext game={pgn} gameIndex={99} />,
34
35
  <Movetext game={database} gameIndex={99} />,
35
36
  <Movetext game={dummyPgn} />,
36
- <Movetext game={kokopu.pgnRead(dummyPgn)} gameIndex={1} />,
37
+ <Movetext game={pgnRead(dummyPgn)} gameIndex={1} />,
37
38
  <Movetext game={42} />,
38
39
  ], 'width-600'); /* eslint-enable react/jsx-key */
@@ -87,8 +87,8 @@ probably to assure himself that the combination was sound and that he had a forc
87
87
  [White "1<sup>st</sup> <em>player</em>"]
88
88
  [Black "2<sub>nd</sub> <i>player</i>"]
89
89
  [Result "*"]
90
- [WhiteElo "<ins>2800</ins>"]
91
- [BlackElo "<del>1010</del>"]
90
+ [WhiteElo "2800"]
91
+ [BlackElo "1010"]
92
92
  [WhiteTitle "<span class=\"myClass\">GM</span>"]
93
93
  [BlackTitle "<span id=\"myId\">no-GM</span>"]
94
94
 
@@ -104,7 +104,7 @@ probably to assure himself that the combination was sound and that he had a forc
104
104
  [Black "?"]
105
105
  [Result "*"]
106
106
 
107
- {I'm a <strong><ins>comment</ins></strong> with some <em class="myClass">HTML content</em> in it.<br/>
107
+ {I'm a <strong><ins>comment</ins></strong> with <del>some</del> <em class="myClass">HTML content</em> in it.<br/>
108
108
  Lists are supported:
109
109
  <ul>
110
110
  <li>1<sup>st</sup> point</li>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kokopu-react",
3
- "version": "1.7.2",
3
+ "version": "1.8.0",
4
4
  "description": "A React-based library to create and display chessboard and chess-related components.",
5
5
  "keywords": [
6
6
  "chess",
@@ -31,7 +31,7 @@
31
31
  ".nycrc.yml"
32
32
  ],
33
33
  "peerDependencies": {
34
- "kokopu": "^2.6.0",
34
+ "kokopu": "^3.0.0",
35
35
  "react": "17.x.x || 18.x.x"
36
36
  },
37
37
  "dependencies": {
@@ -42,22 +42,22 @@
42
42
  },
43
43
  "devDependencies": {
44
44
  "@babel/cli": "^7.18.10",
45
- "@babel/core": "^7.18.10",
45
+ "@babel/core": "^7.18.13",
46
46
  "@babel/preset-env": "^7.18.10",
47
47
  "@babel/preset-react": "^7.18.6",
48
48
  "@emotion/react": "^11.10.0",
49
49
  "@emotion/styled": "^11.10.0",
50
- "@mui/material": "^5.9.3",
50
+ "@mui/material": "^5.10.2",
51
51
  "babel-loader": "^8.2.5",
52
52
  "babel-plugin-istanbul": "^6.1.1",
53
53
  "copy-webpack-plugin": "^11.0.0",
54
54
  "coveralls": "^3.1.1",
55
55
  "css-loader": "^6.7.1",
56
- "eslint": "^8.21.0",
57
- "eslint-plugin-react": "^7.30.1",
56
+ "eslint": "^8.22.0",
57
+ "eslint-plugin-react": "^7.31.0",
58
58
  "html-webpack-plugin": "^5.5.0",
59
59
  "img-diff-js": "^0.5.2",
60
- "kokopu": "^2.9.2",
60
+ "kokopu": "^3.0.0",
61
61
  "mocha": "^10.0.0",
62
62
  "null-loader": "^4.0.1",
63
63
  "nyc": "^15.1.0",
@@ -65,7 +65,7 @@
65
65
  "react-dom": "^18.2.0",
66
66
  "react-styleguidist": "^11.2.0",
67
67
  "selenium-webdriver": "^4.3.1",
68
- "ssh2-sftp-client": "^9.0.2",
68
+ "ssh2-sftp-client": "^9.0.3",
69
69
  "style-loader": "^3.3.1",
70
70
  "unit.js": "^2.1.1",
71
71
  "webpack": "^5.74.0",
package/src/Chessboard.js CHANGED
@@ -24,7 +24,7 @@ import PropTypes from 'prop-types';
24
24
  import React from 'react';
25
25
  import Draggable from 'react-draggable';
26
26
  import { Motion, spring } from 'react-motion';
27
- import kokopu from 'kokopu';
27
+ import { exception, MoveDescriptor, Position, coordinatesToSquare, forEachSquare, oppositeColor, squareColor, squareToCoordinates } from 'kokopu';
28
28
 
29
29
  import colorsets from './impl/colorsets';
30
30
  import piecesets from './impl/piecesets';
@@ -102,7 +102,7 @@ export default class Chessboard extends React.Component {
102
102
 
103
103
  // Render the squares.
104
104
  let squares = [];
105
- kokopu.forEachSquare(sq => squares.push(this.renderSquare(squareSize, colorset, sq)));
105
+ forEachSquare(sq => squares.push(this.renderSquare(squareSize, colorset, sq)));
106
106
 
107
107
  // Render coordinates.
108
108
  let rankCoordinates = [];
@@ -155,12 +155,12 @@ export default class Chessboard extends React.Component {
155
155
  */
156
156
  renderBoardContentAnimated(positionBefore, move, alpha, squareSize, colorset, pieceset) {
157
157
  let pieces = [];
158
- kokopu.forEachSquare(sq => pieces.push(this.renderPieceAnimated(positionBefore, move, alpha, squareSize, pieceset, sq)));
158
+ forEachSquare(sq => pieces.push(this.renderPieceAnimated(positionBefore, move, alpha, squareSize, pieceset, sq)));
159
159
  return (
160
160
  <>
161
161
  {pieces}
162
162
  {this.renderMoveArrow(move, alpha, squareSize, colorset)}
163
- {this.renderTurnFlag(kokopu.oppositeColor(positionBefore.turn()), squareSize, pieceset)}
163
+ {this.renderTurnFlag(oppositeColor(positionBefore.turn()), squareSize, pieceset)}
164
164
  </>
165
165
  );
166
166
  }
@@ -178,7 +178,7 @@ export default class Chessboard extends React.Component {
178
178
  // Render the square-related objects.
179
179
  let pieces = [];
180
180
  let handles = [];
181
- kokopu.forEachSquare(sq => {
181
+ forEachSquare(sq => {
182
182
  pieces.push(this.renderPiece(position, squareSize, pieceset, sq));
183
183
  if (this.props.interactionMode) {
184
184
  handles.push(this.renderSquareHandle(position, squareSize, sq));
@@ -203,7 +203,7 @@ export default class Chessboard extends React.Component {
203
203
 
204
204
  renderSquare(squareSize, colorset, sq) {
205
205
  let { x, y } = this.getSquareCoordinates(squareSize, sq);
206
- return <rect key={sq} x={x} y={y} width={squareSize} height={squareSize} fill={colorset[kokopu.squareColor(sq)]} />;
206
+ return <rect key={sq} x={x} y={y} width={squareSize} height={squareSize} fill={colorset[squareColor(sq)]} />;
207
207
  }
208
208
 
209
209
  renderHoveredSquare(squareSize, colorset) {
@@ -575,7 +575,7 @@ export default class Chessboard extends React.Component {
575
575
  * Return the (x,y) coordinates of the given square in the SVG canvas.
576
576
  */
577
577
  getSquareCoordinates(squareSize, sq) {
578
- let { file, rank } = kokopu.squareToCoordinates(sq);
578
+ let { file, rank } = squareToCoordinates(sq);
579
579
  let x = this.props.flipped ? (7 - file) * squareSize : file * squareSize;
580
580
  let y = this.props.flipped ? rank * squareSize : (7 - rank) * squareSize;
581
581
  return { x: x, y: y };
@@ -604,7 +604,7 @@ export default class Chessboard extends React.Component {
604
604
  }
605
605
 
606
606
  // Compute the position after the move and return the result.
607
- let positionAfter = new kokopu.Position(positionInfo.position);
607
+ let positionAfter = new Position(positionInfo.position);
608
608
  positionAfter.play(moveInfo.move);
609
609
  return { positionError: false, moveError: false, positionBefore: positionInfo.position, move: moveInfo.move, position: positionAfter };
610
610
  }
@@ -615,7 +615,7 @@ export default class Chessboard extends React.Component {
615
615
  getSquareAt(squareSize, x, y) {
616
616
  let file = this.props.flipped ? 7 - Math.floor(x / squareSize) : Math.floor(x / squareSize);
617
617
  let rank = this.props.flipped ? Math.floor(y / squareSize) : 7 - Math.floor(y / squareSize);
618
- return file >= 0 && file < 8 && rank >= 0 && rank < 8 ? kokopu.coordinatesToSquare(file, rank) : '-';
618
+ return file >= 0 && file < 8 && rank >= 0 && rank < 8 ? coordinatesToSquare(file, rank) : '-';
619
619
  }
620
620
 
621
621
  /**
@@ -760,30 +760,26 @@ export default class Chessboard extends React.Component {
760
760
  Chessboard.propTypes = {
761
761
 
762
762
  /**
763
- * Displayed position. Can be a [kokopu.Position](https://kokopu.yo35.org/docs/current/Position.html) object,
763
+ * Displayed position. Can be a [kokopu.Position](https://kokopu.yo35.org/docs/current/classes/Position.html) object,
764
764
  * a [FEN string](https://en.wikipedia.org/wiki/Forsyth%E2%80%93Edwards_Notation),
765
765
  * `'start'` (usual starting position), or `'empty'` (empty board).
766
766
  *
767
767
  * Optionally, the FEN string can be prefixed with `'variant:'`, `variant` corresponding to one of the
768
- * [game variant](https://kokopu.yo35.org/docs/current/global.html#GameVariant) supported by Kokopu. For instance:
768
+ * [game variant](https://kokopu.yo35.org/docs/current/types/GameVariant.html) supported by Kokopu. For instance:
769
769
  * `'chess960:nrkbqrbn/pppppppp/8/8/8/8/PPPPPPPP/NRKBQRBN w KQkq - 0 1'`.
770
770
  */
771
771
  position: PropTypes.oneOfType([
772
- PropTypes.instanceOf(kokopu.Position),
772
+ PropTypes.instanceOf(Position),
773
773
  PropTypes.string
774
774
  ]),
775
775
 
776
776
  /**
777
- * Displayed move (optional), defined either as a [kokopu.MoveDescriptor](https://kokopu.yo35.org/docs/current/MoveDescriptor.html) object
777
+ * Displayed move (optional), defined either as a [kokopu.MoveDescriptor](https://kokopu.yo35.org/docs/current/classes/MoveDescriptor.html) object
778
778
  * or as a [SAN string](https://en.wikipedia.org/wiki/Algebraic_notation_(chess)) (e.g. `'Nf3'`). In both cases, it must represent
779
779
  * a legal move in position defined in attribute `position`.
780
780
  */
781
781
  move: PropTypes.oneOfType([
782
- function(props, propName, componentName) {
783
- if (!kokopu.isMoveDescriptor(props[propName])) {
784
- return new Error(`Invalid prop ${propName} supplied to ${componentName}. Validation failed.`);
785
- }
786
- },
782
+ PropTypes.instanceOf(MoveDescriptor),
787
783
  PropTypes.string
788
784
  ]),
789
785
 
@@ -961,16 +957,16 @@ function computeCoordinateFontSize(squareSize) {
961
957
  * Try to interpret the given object as a chess position.
962
958
  */
963
959
  function parsePosition(position) {
964
- if (position instanceof kokopu.Position) {
960
+ if (position instanceof Position) {
965
961
  return { error: false, position: position };
966
962
  }
967
963
  else if (typeof position === 'string') {
968
964
  try {
969
- return { error: false, position: new kokopu.Position(position) };
965
+ return { error: false, position: new Position(position) };
970
966
  }
971
967
  catch (e) {
972
968
  // istanbul ignore else
973
- if (e instanceof kokopu.exception.InvalidFEN) {
969
+ if (e instanceof exception.InvalidFEN) {
974
970
  return { error: true, message: e.message };
975
971
  }
976
972
  else {
@@ -988,7 +984,7 @@ function parsePosition(position) {
988
984
  * Try to interpret the given object `move` as a move descriptor based on the given position.
989
985
  */
990
986
  function parseMove(position, move) {
991
- if (kokopu.isMoveDescriptor(move)) {
987
+ if (move instanceof MoveDescriptor) {
992
988
  return { error: false, move: move };
993
989
  }
994
990
  else if (typeof move === 'string') {
@@ -997,7 +993,7 @@ function parseMove(position, move) {
997
993
  }
998
994
  catch (e) {
999
995
  // istanbul ignore else
1000
- if (e instanceof kokopu.exception.InvalidNotation) {
996
+ if (e instanceof exception.InvalidNotation) {
1001
997
  return { error: true, message: e.message };
1002
998
  }
1003
999
  else {
package/src/ErrorBox.js CHANGED
@@ -24,6 +24,7 @@ import PropTypes from 'prop-types';
24
24
  import React from 'react';
25
25
 
26
26
  import i18n from './i18n';
27
+ import { fillPlaceholder } from './impl/util';
27
28
 
28
29
  import './css/error_box.css';
29
30
 
@@ -125,7 +126,7 @@ function ellipsisAt(text, pos, backwardCharacters, forwardCharacters, lineNumber
125
126
  excerpt = excerpt.replace(/\n|\r|\t/g, ' ');
126
127
  let secondLine = Array(1 + e1.length + pos - p1).join(' ') + '^';
127
128
  if (lineNumber) {
128
- secondLine += ' (' + i18n.LINE.replace(/\{0\}/g, lineNumber) + ')';
129
+ secondLine += ` (${fillPlaceholder(i18n.LINE, lineNumber)})`;
129
130
  }
130
131
  return excerpt + '\n' + secondLine;
131
132
  }
package/src/Movetext.js CHANGED
@@ -22,9 +22,10 @@
22
22
 
23
23
  import PropTypes from 'prop-types';
24
24
  import React from 'react';
25
- import kokopu from 'kokopu';
25
+ import { exception, Database, Game, nagSymbol, pgnRead } from 'kokopu';
26
26
 
27
27
  import HtmlSanitizer from './impl/HtmlSanitizer';
28
+ import { fillPlaceholder } from './impl/util';
28
29
  import Chessboard from './Chessboard';
29
30
  import ErrorBox from './ErrorBox';
30
31
  import { moveFormatter } from './formatmove';
@@ -85,7 +86,7 @@ export default class Movetext extends React.Component {
85
86
  let colorTag = <span className="kokopu-colorTag"></span>;
86
87
  let playerNameElement = <span className="kokopu-header-playerName">{sanitizeHtml(playerName)}</span>;
87
88
  let titleElement = title === undefined ? undefined : <span className="kokopu-header-playerTitle">{sanitizeHtml(title)}</span>;
88
- let ratingElement = rating === undefined ? undefined : <span className="kokopu-header-playerRating">{sanitizeHtml(rating)}</span>;
89
+ let ratingElement = rating === undefined ? undefined : <span className="kokopu-header-playerRating">{rating}</span>;
89
90
  let separator = title === undefined || rating === undefined ? undefined : '\u00a0'; // \u00a0 == &nbsp;
90
91
  let titleRatingGroup = title === undefined && rating === undefined ? undefined : <span className="kokopu-headerGroup-titleRating">{titleElement}{separator}{ratingElement}</span>;
91
92
  return <div className={classNames.join(' ')} key={'player-' + color}>{colorTag}{playerNameElement}{titleRatingGroup}</div>;
@@ -128,7 +129,7 @@ export default class Movetext extends React.Component {
128
129
  if (annotator === undefined) {
129
130
  return undefined;
130
131
  }
131
- annotator = i18n.ANNOTATED_BY.replace(/\{0\}/g, annotator);
132
+ annotator = fillPlaceholder(i18n.ANNOTATED_BY, annotator);
132
133
  return <div className="kokopu-header-annotator" key="annotator">{sanitizeHtml(annotator)}</div>;
133
134
  }
134
135
 
@@ -255,7 +256,7 @@ export default class Movetext extends React.Component {
255
256
  let notationText = notationTextBuilder(node.notation());
256
257
 
257
258
  // NAGs
258
- let nagElements = node.nags().map(nag => <span className="kokopu-nag" key={nag}>{kokopu.nagSymbol(nag)}</span>);
259
+ let nagElements = node.nags().map(nag => <span className="kokopu-nag" key={nag}>{nagSymbol(nag)}</span>);
259
260
 
260
261
  // Class
261
262
  let nodeId = node.id();
@@ -482,18 +483,18 @@ export default class Movetext extends React.Component {
482
483
  Movetext.propTypes = {
483
484
 
484
485
  /**
485
- * Displayed position. Can be a [kokopu.Game](https://kokopu.yo35.org/docs/current/Game.html) object,
486
- * a [kokopu.Database](https://kokopu.yo35.org/docs/current/Database.html) object,
486
+ * Displayed position. Can be a [kokopu.Game](https://kokopu.yo35.org/docs/current/classes/Game.html) object,
487
+ * a [kokopu.Database](https://kokopu.yo35.org/docs/current/classes/Database.html) object,
487
488
  * or a [PGN string](https://en.wikipedia.org/wiki/Portable_Game_Notation).
488
489
  */
489
490
  game: PropTypes.oneOfType([
490
- PropTypes.instanceOf(kokopu.Game),
491
- PropTypes.instanceOf(kokopu.Database),
491
+ PropTypes.instanceOf(Game),
492
+ PropTypes.instanceOf(Database),
492
493
  PropTypes.string
493
494
  ]),
494
495
 
495
496
  /**
496
- * Index of the game to display (only if attribute `game` is a [kokopu.Database](https://kokopu.yo35.org/docs/current/Database.html)
497
+ * Index of the game to display (only if attribute `game` is a [kokopu.Database](https://kokopu.yo35.org/docs/current/classes/Database.html)
497
498
  * or a [PGN string](https://en.wikipedia.org/wiki/Portable_Game_Notation)): `0` for the first game of the database/PGN, `1` for the second one, etc.
498
499
  * If omitted, the first game of the database/PGN is displayed.
499
500
  */
@@ -542,7 +543,7 @@ Movetext.propTypes = {
542
543
 
543
544
  /**
544
545
  * ID of the selected move (or `'start'` for the beginning of the main variation).
545
- * Use [kokopu.Node#id](https://kokopu.yo35.org/docs/current/Node.html#id) to get the ID of a game move.
546
+ * Use [kokopu.Node#id](https://kokopu.yo35.org/docs/current/classes/Node.html#id) to get the ID of a game move.
546
547
  */
547
548
  selection: PropTypes.string,
548
549
 
@@ -556,7 +557,7 @@ Movetext.propTypes = {
556
557
  /**
557
558
  * Callback invoked when the user selects a move (only if `interactionMode` is set to `'selectMove'`).
558
559
  *
559
- * @param {string?} nodeId ID of the selected move (as returned by [kokopu.Node#id](https://kokopu.yo35.org/docs/current/Node.html#id)),
560
+ * @param {string?} nodeId ID of the selected move (as returned by [kokopu.Node#id](https://kokopu.yo35.org/docs/current/classes/Node.html#id)),
560
561
  * `'start'` for the beginning of the main variation, or `undefined` if the user unselects the previously selected move.
561
562
  * @param {string} evtOrigin Origin of the event. Can be:
562
563
  * - `'key-first'`: the event has been triggered by the "go-to-first-move" key (aka. the home key),
@@ -570,7 +571,7 @@ Movetext.propTypes = {
570
571
 
571
572
 
572
573
  Movetext.defaultProps = {
573
- game: new kokopu.Game(),
574
+ game: new Game(),
574
575
  gameIndex: 0,
575
576
  diagramOptions: {},
576
577
  pieceSymbols: 'native',
@@ -643,17 +644,20 @@ function sanitizeHtml(text, sanitizer) {
643
644
  * Try to interpret the given object as a chess game.
644
645
  */
645
646
  function parseGame(game, gameIndex) {
646
- if (game instanceof kokopu.Game) {
647
+ if (game instanceof Game) {
647
648
  return { error: false, game: game };
648
649
  }
649
- else if (game instanceof kokopu.Database || typeof game === 'string') {
650
+ else if (game instanceof Database || typeof game === 'string') {
651
+ if (!Number.isInteger(gameIndex) || gameIndex < 0) {
652
+ return { error: true, message: i18n.INVALID_GAME_INDEX_ATTRIBUTE_ERROR_MESSAGE };
653
+ }
650
654
  try {
651
- let result = game instanceof kokopu.Database ? game.game(gameIndex) : kokopu.pgnRead(game, gameIndex);
655
+ const result = game instanceof Database ? game.game(gameIndex) : pgnRead(game, gameIndex);
652
656
  return { error: false, game: result };
653
657
  }
654
658
  catch (e) {
655
659
  // istanbul ignore else
656
- if (e instanceof kokopu.exception.InvalidPGN) {
660
+ if (e instanceof exception.InvalidPGN) {
657
661
  return { error: true, message: e.message, text: e.pgn, errorIndex: e.index, lineNumber: e.lineNumber };
658
662
  }
659
663
  else {
package/src/i18n.js CHANGED
@@ -36,6 +36,7 @@ const i18n = {
36
36
  ANNOTATED_BY: 'Annotated by {0}',
37
37
  INVALID_PGN_ERROR_TITLE: 'Invalid PGN string.',
38
38
  INVALID_GAME_ATTRIBUTE_ERROR_MESSAGE: 'Invalid "game" attribute.',
39
+ INVALID_GAME_INDEX_ATTRIBUTE_ERROR_MESSAGE: 'Invalid "game index" attribute.',
39
40
  };
40
41
 
41
42
  export default i18n;
package/src/impl/util.js CHANGED
@@ -35,6 +35,14 @@ export function generateRandomId() {
35
35
  }
36
36
 
37
37
 
38
+ export function fillPlaceholder(message, ...placeholderValues) {
39
+ return message.replace(/{(\d+)}/g, (match, placeholder) => {
40
+ const placeholderIndex = Number(placeholder);
41
+ return placeholderIndex < placeholderValues.length ? placeholderValues[placeholderIndex] : match;
42
+ });
43
+ }
44
+
45
+
38
46
  export function sanitizeInteger(input, min, max) {
39
47
  return Math.min(Math.max(Math.round(input), min), max);
40
48
  }
@@ -36,7 +36,7 @@ describe('Movetext graphic', function() {
36
36
  });
37
37
 
38
38
  itChecksScreenshots(browserContext, '12_movetext_simple', [ 'game-0', 'game-1', 'game-2', 'game-3' ]);
39
- itChecksScreenshots(browserContext, '13_movetext_error', [ 'wrong-game-index', 'pgn-parsing-error-1', 'pgn-parsing-error-2', 'wrong type' ]);
39
+ itChecksScreenshots(browserContext, '13_movetext_error', [ 'wrong-game-index-1', 'wrong-game-index-2', 'pgn-parsing-error-1', 'pgn-parsing-error-2', 'wrong type' ]);
40
40
  itChecksScreenshots(browserContext, '14_movetext_html', [ 'html-in-headers', 'html-in-comments', 'filtered-tags-and-attributes' ]);
41
41
  itChecksScreenshots(browserContext, '15_movetext_options', [ 'localized-piece-symbols', 'custom-piece-symbols', 'figurine-piece-symbols-and-diagram-options',
42
42
  'hidden-diagrams' ]);