@lichess-org/pgn-viewer 2.4.7 → 2.5.1

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.
Files changed (52) hide show
  1. package/README.md +23 -0
  2. package/demo/frame.html +1 -1
  3. package/demo/index.html +1 -1
  4. package/demo/lichess-pgn-viewer.css +61 -28
  5. package/demo/lichess-pgn-viewer.js +697 -379
  6. package/demo/one.html +6 -6
  7. package/demo/one.js +1 -1
  8. package/dist/interfaces.d.ts +2 -1
  9. package/dist/lichess-pgn-viewer.css +1 -1
  10. package/dist/lichess-pgn-viewer.min.js +4 -4
  11. package/dist/pgnViewer.d.ts +1 -0
  12. package/dist/pgnViewer.js +4 -0
  13. package/dist/pgnViewer.js.map +1 -1
  14. package/dist/translation.d.ts +2 -2
  15. package/dist/translation.js +51 -3
  16. package/dist/translation.js.map +1 -1
  17. package/dist/tsconfig.tsbuildinfo +1 -1
  18. package/dist/view/accessibleBoard.d.ts +3 -0
  19. package/dist/view/accessibleBoard.js +40 -0
  20. package/dist/view/accessibleBoard.js.map +1 -0
  21. package/dist/view/aria.d.ts +10 -0
  22. package/dist/view/aria.js +54 -0
  23. package/dist/view/aria.js.map +1 -0
  24. package/dist/view/glyph.d.ts +9 -0
  25. package/dist/view/glyph.js +1 -1
  26. package/dist/view/glyph.js.map +1 -1
  27. package/dist/view/main.js +9 -0
  28. package/dist/view/main.js.map +1 -1
  29. package/dist/view/menu.d.ts +3 -2
  30. package/dist/view/menu.js +76 -11
  31. package/dist/view/menu.js.map +1 -1
  32. package/dist/view/player.js +15 -10
  33. package/dist/view/player.js.map +1 -1
  34. package/dist/view/side.js +29 -14
  35. package/dist/view/side.js.map +1 -1
  36. package/dist/view/util.d.ts +5 -0
  37. package/dist/view/util.js +63 -0
  38. package/dist/view/util.js.map +1 -1
  39. package/package.json +13 -14
  40. package/scss/_side.scss +19 -4
  41. package/scss/_util.scss +10 -0
  42. package/src/interfaces.ts +2 -2
  43. package/src/pgnViewer.ts +6 -0
  44. package/src/translation.ts +53 -4
  45. package/src/view/accessibleBoard.ts +61 -0
  46. package/src/view/aria.ts +68 -0
  47. package/src/view/glyph.ts +1 -1
  48. package/src/view/main.ts +13 -0
  49. package/src/view/menu.ts +139 -61
  50. package/src/view/player.ts +19 -13
  51. package/src/view/side.ts +40 -16
  52. package/src/view/util.ts +66 -0
@@ -1,4 +1,4 @@
1
- // node_modules/.pnpm/chessops@0.14.2/node_modules/chessops/dist/esm/types.js
1
+ // node_modules/.pnpm/chessops@0.15.0/node_modules/chessops/dist/esm/types.js
2
2
  var FILE_NAMES = ["a", "b", "c", "d", "e", "f", "g", "h"];
3
3
  var RANK_NAMES = ["1", "2", "3", "4", "5", "6", "7", "8"];
4
4
  var COLORS = ["white", "black"];
@@ -6,7 +6,7 @@ var ROLES = ["pawn", "knight", "bishop", "rook", "queen", "king"];
6
6
  var CASTLING_SIDES = ["a", "h"];
7
7
  var isDrop = (v) => "role" in v;
8
8
 
9
- // node_modules/.pnpm/chessops@0.14.2/node_modules/chessops/dist/esm/util.js
9
+ // node_modules/.pnpm/chessops@0.15.0/node_modules/chessops/dist/esm/util.js
10
10
  var defined = (v) => v !== void 0;
11
11
  var opposite = (color) => color === "white" ? "black" : "white";
12
12
  var squareRank = (square) => square >> 3;
@@ -56,21 +56,21 @@ var makeUci = (move3) => isDrop(move3) ? `${roleToChar(move3.role).toUpperCase()
56
56
  var kingCastlesTo = (color, side) => color === "white" ? side === "a" ? 2 : 6 : side === "a" ? 58 : 62;
57
57
  var rookCastlesTo = (color, side) => color === "white" ? side === "a" ? 3 : 5 : side === "a" ? 59 : 61;
58
58
 
59
- // node_modules/.pnpm/chessops@0.14.2/node_modules/chessops/dist/esm/squareSet.js
60
- var popcnt32 = (n2) => {
61
- n2 = n2 - (n2 >>> 1 & 1431655765);
62
- n2 = (n2 & 858993459) + (n2 >>> 2 & 858993459);
63
- return Math.imul(n2 + (n2 >>> 4) & 252645135, 16843009) >> 24;
59
+ // node_modules/.pnpm/chessops@0.15.0/node_modules/chessops/dist/esm/squareSet.js
60
+ var popcnt32 = (n) => {
61
+ n = n - (n >>> 1 & 1431655765);
62
+ n = (n & 858993459) + (n >>> 2 & 858993459);
63
+ return Math.imul(n + (n >>> 4) & 252645135, 16843009) >> 24;
64
64
  };
65
- var bswap32 = (n2) => {
66
- n2 = n2 >>> 8 & 16711935 | (n2 & 16711935) << 8;
67
- return n2 >>> 16 & 65535 | (n2 & 65535) << 16;
65
+ var bswap32 = (n) => {
66
+ n = n >>> 8 & 16711935 | (n & 16711935) << 8;
67
+ return n >>> 16 & 65535 | (n & 65535) << 16;
68
68
  };
69
- var rbit32 = (n2) => {
70
- n2 = n2 >>> 1 & 1431655765 | (n2 & 1431655765) << 1;
71
- n2 = n2 >>> 2 & 858993459 | (n2 & 858993459) << 2;
72
- n2 = n2 >>> 4 & 252645135 | (n2 & 252645135) << 4;
73
- return bswap32(n2);
69
+ var rbit32 = (n) => {
70
+ n = n >>> 1 & 1431655765 | (n & 1431655765) << 1;
71
+ n = n >>> 2 & 858993459 | (n & 858993459) << 2;
72
+ n = n >>> 4 & 252645135 | (n & 252645135) << 4;
73
+ return bswap32(n);
74
74
  };
75
75
  var SquareSet = class _SquareSet {
76
76
  constructor(lo, hi) {
@@ -248,7 +248,7 @@ var SquareSet = class _SquareSet {
248
248
  }
249
249
  };
250
250
 
251
- // node_modules/.pnpm/chessops@0.14.2/node_modules/chessops/dist/esm/attacks.js
251
+ // node_modules/.pnpm/chessops@0.15.0/node_modules/chessops/dist/esm/attacks.js
252
252
  var computeRange = (square, deltas) => {
253
253
  let range = SquareSet.empty();
254
254
  for (const delta of deltas) {
@@ -338,7 +338,7 @@ var ray = (a, b) => {
338
338
  };
339
339
  var between = (a, b) => ray(a, b).intersect(SquareSet.full().shl64(a).xor(SquareSet.full().shl64(b))).withoutFirst();
340
340
 
341
- // node_modules/.pnpm/chessops@0.14.2/node_modules/chessops/dist/esm/board.js
341
+ // node_modules/.pnpm/chessops@0.15.0/node_modules/chessops/dist/esm/board.js
342
342
  var Board = class _Board {
343
343
  constructor() {
344
344
  }
@@ -451,6 +451,12 @@ var Board = class _Board {
451
451
  bishopsAndQueens() {
452
452
  return this.bishop.union(this.queen);
453
453
  }
454
+ steppers() {
455
+ return this.knight.union(this.pawn).union(this.king);
456
+ }
457
+ sliders() {
458
+ return this.bishop.union(this.rook).union(this.queen);
459
+ }
454
460
  /**
455
461
  * Finds the unique king of the given `color`, if any.
456
462
  */
@@ -459,7 +465,7 @@ var Board = class _Board {
459
465
  }
460
466
  };
461
467
 
462
- // node_modules/.pnpm/chessops@0.14.2/node_modules/chessops/dist/esm/setup.js
468
+ // node_modules/.pnpm/chessops@0.15.0/node_modules/chessops/dist/esm/setup.js
463
469
  var MaterialSide = class _MaterialSide {
464
470
  constructor() {
465
471
  }
@@ -570,63 +576,81 @@ var RemainingChecks = class _RemainingChecks {
570
576
  }
571
577
  };
572
578
 
573
- // node_modules/.pnpm/@badrap+result@0.2.13/node_modules/@badrap/result/dist/index.modern.mjs
574
- var r = class {
575
- unwrap(r2, t2) {
576
- const e2 = this._chain((t3) => n.ok(r2 ? r2(t3) : t3), (r3) => t2 ? n.ok(t2(r3)) : n.err(r3));
577
- if (e2.isErr) throw e2.error;
578
- return e2.value;
579
+ // node_modules/.pnpm/@badrap+result@0.3.1/node_modules/@badrap/result/dist/mjs/index.mjs
580
+ var _Result = class {
581
+ unwrap(ok, err) {
582
+ const r = this._chain((value) => Result.ok(ok ? ok(value) : value), (error) => err ? Result.ok(err(error)) : Result.err(error));
583
+ if (r.isErr) {
584
+ throw r.error;
585
+ }
586
+ return r.value;
579
587
  }
580
- map(r2, t2) {
581
- return this._chain((t3) => n.ok(r2(t3)), (r3) => n.err(t2 ? t2(r3) : r3));
588
+ map(ok, err) {
589
+ return this._chain((value) => Result.ok(ok(value)), (error) => Result.err(err ? err(error) : error));
582
590
  }
583
- chain(r2, t2) {
584
- return this._chain(r2, t2 || ((r3) => n.err(r3)));
591
+ chain(ok, err) {
592
+ return this._chain(ok, err !== null && err !== void 0 ? err : ((error) => Result.err(error)));
585
593
  }
586
594
  };
587
- var t = class extends r {
588
- constructor(r2) {
589
- super(), this.value = void 0, this.isOk = true, this.isErr = false, this.value = r2;
595
+ var _Ok = class extends _Result {
596
+ constructor(value) {
597
+ super();
598
+ this.value = value;
599
+ this.isOk = true;
600
+ this.isErr = false;
590
601
  }
591
- _chain(r2, t2) {
592
- return r2(this.value);
602
+ _chain(ok, _err) {
603
+ return ok(this.value);
593
604
  }
594
605
  };
595
- var e = class extends r {
596
- constructor(r2) {
597
- super(), this.error = void 0, this.isOk = false, this.isErr = true, this.error = r2;
606
+ var _Err = class extends _Result {
607
+ constructor(error) {
608
+ super();
609
+ this.error = error;
610
+ this.isOk = false;
611
+ this.isErr = true;
598
612
  }
599
- _chain(r2, t2) {
600
- return t2(this.error);
613
+ _chain(_ok, err) {
614
+ return err(this.error);
601
615
  }
602
616
  };
603
- var n;
604
- !function(r2) {
605
- r2.ok = function(r3) {
606
- return new t(r3);
607
- }, r2.err = function(r3) {
608
- return new e(r3 || new Error());
609
- }, r2.all = function(t2) {
610
- if (Array.isArray(t2)) {
611
- const e3 = [];
612
- for (let r3 = 0; r3 < t2.length; r3++) {
613
- const n3 = t2[r3];
614
- if (n3.isErr) return n3;
615
- e3.push(n3.value);
617
+ var Result;
618
+ (function(Result2) {
619
+ function ok(value) {
620
+ return new _Ok(value);
621
+ }
622
+ Result2.ok = ok;
623
+ function err(error) {
624
+ return new _Err(error || new Error());
625
+ }
626
+ Result2.err = err;
627
+ function all(obj) {
628
+ if (Array.isArray(obj)) {
629
+ const res2 = [];
630
+ for (let i = 0; i < obj.length; i++) {
631
+ const item = obj[i];
632
+ if (item.isErr) {
633
+ return item;
634
+ }
635
+ res2.push(item.value);
616
636
  }
617
- return r2.ok(e3);
637
+ return Result2.ok(res2);
618
638
  }
619
- const e2 = {}, n2 = Object.keys(t2);
620
- for (let r3 = 0; r3 < n2.length; r3++) {
621
- const s = t2[n2[r3]];
622
- if (s.isErr) return s;
623
- e2[n2[r3]] = s.value;
639
+ const res = {};
640
+ const keys = Object.keys(obj);
641
+ for (let i = 0; i < keys.length; i++) {
642
+ const item = obj[keys[i]];
643
+ if (item.isErr) {
644
+ return item;
645
+ }
646
+ res[keys[i]] = item.value;
624
647
  }
625
- return r2.ok(e2);
626
- };
627
- }(n || (n = {}));
648
+ return Result2.ok(res);
649
+ }
650
+ Result2.all = all;
651
+ })(Result || (Result = {}));
628
652
 
629
- // node_modules/.pnpm/chessops@0.14.2/node_modules/chessops/dist/esm/chess.js
653
+ // node_modules/.pnpm/chessops@0.15.0/node_modules/chessops/dist/esm/chess.js
630
654
  var IllegalSetup;
631
655
  (function(IllegalSetup2) {
632
656
  IllegalSetup2["Empty"] = "ERR_EMPTY";
@@ -805,21 +829,21 @@ var Position = class {
805
829
  }
806
830
  validate() {
807
831
  if (this.board.occupied.isEmpty())
808
- return n.err(new PositionError(IllegalSetup.Empty));
832
+ return Result.err(new PositionError(IllegalSetup.Empty));
809
833
  if (this.board.king.size() !== 2)
810
- return n.err(new PositionError(IllegalSetup.Kings));
834
+ return Result.err(new PositionError(IllegalSetup.Kings));
811
835
  if (!defined(this.board.kingOf(this.turn)))
812
- return n.err(new PositionError(IllegalSetup.Kings));
836
+ return Result.err(new PositionError(IllegalSetup.Kings));
813
837
  const otherKing = this.board.kingOf(opposite(this.turn));
814
838
  if (!defined(otherKing))
815
- return n.err(new PositionError(IllegalSetup.Kings));
839
+ return Result.err(new PositionError(IllegalSetup.Kings));
816
840
  if (this.kingAttackers(otherKing, this.turn, this.board.occupied).nonEmpty()) {
817
- return n.err(new PositionError(IllegalSetup.OppositeCheck));
841
+ return Result.err(new PositionError(IllegalSetup.OppositeCheck));
818
842
  }
819
843
  if (SquareSet.backranks().intersects(this.board.pawn)) {
820
- return n.err(new PositionError(IllegalSetup.PawnsOnBackrank));
844
+ return Result.err(new PositionError(IllegalSetup.PawnsOnBackrank));
821
845
  }
822
- return n.ok(void 0);
846
+ return Result.ok(void 0);
823
847
  }
824
848
  dropDests(_ctx) {
825
849
  return SquareSet.empty();
@@ -1167,10 +1191,10 @@ var normalizeMove = (pos, move3) => {
1167
1191
  };
1168
1192
  };
1169
1193
 
1170
- // node_modules/.pnpm/chessops@0.14.2/node_modules/chessops/dist/esm/compat.js
1194
+ // node_modules/.pnpm/chessops@0.15.0/node_modules/chessops/dist/esm/compat.js
1171
1195
  var scalachessCharPair = (move3) => isDrop(move3) ? String.fromCharCode(35 + move3.to, 35 + 64 + 8 * 5 + ["queen", "rook", "bishop", "knight", "pawn"].indexOf(move3.role)) : String.fromCharCode(35 + move3.from, move3.promotion ? 35 + 64 + 8 * ["queen", "rook", "bishop", "knight", "king"].indexOf(move3.promotion) + squareFile(move3.to) : 35 + move3.to);
1172
1196
 
1173
- // node_modules/.pnpm/chessops@0.14.2/node_modules/chessops/dist/esm/fen.js
1197
+ // node_modules/.pnpm/chessops@0.15.0/node_modules/chessops/dist/esm/fen.js
1174
1198
  var INITIAL_BOARD_FEN = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR";
1175
1199
  var INITIAL_EPD = INITIAL_BOARD_FEN + " w KQkq -";
1176
1200
  var INITIAL_FEN = INITIAL_EPD + " 0 1";
@@ -1191,9 +1215,9 @@ var InvalidFen;
1191
1215
  })(InvalidFen || (InvalidFen = {}));
1192
1216
  var FenError = class extends Error {
1193
1217
  };
1194
- var nthIndexOf = (haystack, needle, n2) => {
1218
+ var nthIndexOf = (haystack, needle, n) => {
1195
1219
  let index = haystack.indexOf(needle);
1196
- while (n2-- > 0) {
1220
+ while (n-- > 0) {
1197
1221
  if (index === -1)
1198
1222
  break;
1199
1223
  index = haystack.indexOf(needle, index + needle.length);
@@ -1220,11 +1244,11 @@ var parseBoardFen = (boardPart) => {
1220
1244
  file += step2;
1221
1245
  else {
1222
1246
  if (file >= 8 || rank < 0)
1223
- return n.err(new FenError(InvalidFen.Board));
1247
+ return Result.err(new FenError(InvalidFen.Board));
1224
1248
  const square = file + rank * 8;
1225
1249
  const piece = charToPiece(c);
1226
1250
  if (!piece)
1227
- return n.err(new FenError(InvalidFen.Board));
1251
+ return Result.err(new FenError(InvalidFen.Board));
1228
1252
  if (boardPart[i + 1] === "~") {
1229
1253
  piece.promoted = true;
1230
1254
  i++;
@@ -1235,25 +1259,25 @@ var parseBoardFen = (boardPart) => {
1235
1259
  }
1236
1260
  }
1237
1261
  if (rank !== 0 || file !== 8)
1238
- return n.err(new FenError(InvalidFen.Board));
1239
- return n.ok(board);
1262
+ return Result.err(new FenError(InvalidFen.Board));
1263
+ return Result.ok(board);
1240
1264
  };
1241
1265
  var parsePockets = (pocketPart) => {
1242
1266
  if (pocketPart.length > 64)
1243
- return n.err(new FenError(InvalidFen.Pockets));
1267
+ return Result.err(new FenError(InvalidFen.Pockets));
1244
1268
  const pockets = Material.empty();
1245
1269
  for (const c of pocketPart) {
1246
1270
  const piece = charToPiece(c);
1247
1271
  if (!piece)
1248
- return n.err(new FenError(InvalidFen.Pockets));
1272
+ return Result.err(new FenError(InvalidFen.Pockets));
1249
1273
  pockets[piece.color][piece.role]++;
1250
1274
  }
1251
- return n.ok(pockets);
1275
+ return Result.ok(pockets);
1252
1276
  };
1253
1277
  var parseCastlingFen = (board, castlingPart) => {
1254
1278
  let castlingRights = SquareSet.empty();
1255
1279
  if (castlingPart === "-")
1256
- return n.ok(castlingRights);
1280
+ return Result.ok(castlingRights);
1257
1281
  for (const c of castlingPart) {
1258
1282
  const lower = c.toLowerCase();
1259
1283
  const color = c === lower ? "black" : "white";
@@ -1265,12 +1289,12 @@ var parseCastlingFen = (board, castlingPart) => {
1265
1289
  const candidate = lower === "k" ? rooksAndKings.last() : rooksAndKings.first();
1266
1290
  castlingRights = castlingRights.with(defined(candidate) && board.rook.has(candidate) ? candidate : squareFromCoords(lower === "k" ? 7 : 0, rank));
1267
1291
  } else
1268
- return n.err(new FenError(InvalidFen.Castling));
1292
+ return Result.err(new FenError(InvalidFen.Castling));
1269
1293
  }
1270
1294
  if (COLORS.some((color) => SquareSet.backrank(color).intersect(castlingRights).size() > 2)) {
1271
- return n.err(new FenError(InvalidFen.Castling));
1295
+ return Result.err(new FenError(InvalidFen.Castling));
1272
1296
  }
1273
- return n.ok(castlingRights);
1297
+ return Result.ok(castlingRights);
1274
1298
  };
1275
1299
  var parseRemainingChecks = (part) => {
1276
1300
  const parts = part.split("+");
@@ -1278,28 +1302,28 @@ var parseRemainingChecks = (part) => {
1278
1302
  const white = parseSmallUint(parts[1]);
1279
1303
  const black = parseSmallUint(parts[2]);
1280
1304
  if (!defined(white) || white > 3 || !defined(black) || black > 3) {
1281
- return n.err(new FenError(InvalidFen.RemainingChecks));
1305
+ return Result.err(new FenError(InvalidFen.RemainingChecks));
1282
1306
  }
1283
- return n.ok(new RemainingChecks(3 - white, 3 - black));
1307
+ return Result.ok(new RemainingChecks(3 - white, 3 - black));
1284
1308
  } else if (parts.length === 2) {
1285
1309
  const white = parseSmallUint(parts[0]);
1286
1310
  const black = parseSmallUint(parts[1]);
1287
1311
  if (!defined(white) || white > 3 || !defined(black) || black > 3) {
1288
- return n.err(new FenError(InvalidFen.RemainingChecks));
1312
+ return Result.err(new FenError(InvalidFen.RemainingChecks));
1289
1313
  }
1290
- return n.ok(new RemainingChecks(white, black));
1314
+ return Result.ok(new RemainingChecks(white, black));
1291
1315
  } else
1292
- return n.err(new FenError(InvalidFen.RemainingChecks));
1316
+ return Result.err(new FenError(InvalidFen.RemainingChecks));
1293
1317
  };
1294
1318
  var parseFen = (fen) => {
1295
1319
  const parts = fen.split(/[\s_]+/);
1296
1320
  const boardPart = parts.shift();
1297
1321
  let board;
1298
- let pockets = n.ok(void 0);
1322
+ let pockets = Result.ok(void 0);
1299
1323
  if (boardPart.endsWith("]")) {
1300
1324
  const pocketStart = boardPart.indexOf("[");
1301
1325
  if (pocketStart === -1)
1302
- return n.err(new FenError(InvalidFen.Fen));
1326
+ return Result.err(new FenError(InvalidFen.Fen));
1303
1327
  board = parseBoardFen(boardPart.slice(0, pocketStart));
1304
1328
  pockets = parsePockets(boardPart.slice(pocketStart + 1, -1));
1305
1329
  } else {
@@ -1318,16 +1342,16 @@ var parseFen = (fen) => {
1318
1342
  else if (turnPart === "b")
1319
1343
  turn = "black";
1320
1344
  else
1321
- return n.err(new FenError(InvalidFen.Turn));
1345
+ return Result.err(new FenError(InvalidFen.Turn));
1322
1346
  return board.chain((board2) => {
1323
1347
  const castlingPart = parts.shift();
1324
- const castlingRights = defined(castlingPart) ? parseCastlingFen(board2, castlingPart) : n.ok(SquareSet.empty());
1348
+ const castlingRights = defined(castlingPart) ? parseCastlingFen(board2, castlingPart) : Result.ok(SquareSet.empty());
1325
1349
  const epPart = parts.shift();
1326
1350
  let epSquare;
1327
1351
  if (defined(epPart) && epPart !== "-") {
1328
1352
  epSquare = parseSquare(epPart);
1329
1353
  if (!defined(epSquare))
1330
- return n.err(new FenError(InvalidFen.EpSquare));
1354
+ return Result.err(new FenError(InvalidFen.EpSquare));
1331
1355
  }
1332
1356
  let halfmovePart = parts.shift();
1333
1357
  let earlyRemainingChecks;
@@ -1337,22 +1361,22 @@ var parseFen = (fen) => {
1337
1361
  }
1338
1362
  const halfmoves = defined(halfmovePart) ? parseSmallUint(halfmovePart) : 0;
1339
1363
  if (!defined(halfmoves))
1340
- return n.err(new FenError(InvalidFen.Halfmoves));
1364
+ return Result.err(new FenError(InvalidFen.Halfmoves));
1341
1365
  const fullmovesPart = parts.shift();
1342
1366
  const fullmoves = defined(fullmovesPart) ? parseSmallUint(fullmovesPart) : 1;
1343
1367
  if (!defined(fullmoves))
1344
- return n.err(new FenError(InvalidFen.Fullmoves));
1368
+ return Result.err(new FenError(InvalidFen.Fullmoves));
1345
1369
  const remainingChecksPart = parts.shift();
1346
- let remainingChecks = n.ok(void 0);
1370
+ let remainingChecks = Result.ok(void 0);
1347
1371
  if (defined(remainingChecksPart)) {
1348
1372
  if (defined(earlyRemainingChecks))
1349
- return n.err(new FenError(InvalidFen.RemainingChecks));
1373
+ return Result.err(new FenError(InvalidFen.RemainingChecks));
1350
1374
  remainingChecks = parseRemainingChecks(remainingChecksPart);
1351
1375
  } else if (defined(earlyRemainingChecks)) {
1352
1376
  remainingChecks = earlyRemainingChecks;
1353
1377
  }
1354
1378
  if (parts.length > 0)
1355
- return n.err(new FenError(InvalidFen.Fen));
1379
+ return Result.err(new FenError(InvalidFen.Fen));
1356
1380
  return pockets.chain((pockets2) => castlingRights.chain((castlingRights2) => remainingChecks.map((remainingChecks2) => {
1357
1381
  return {
1358
1382
  board: board2,
@@ -1368,12 +1392,12 @@ var parseFen = (fen) => {
1368
1392
  });
1369
1393
  };
1370
1394
  var makePiece = (piece) => {
1371
- let r2 = roleToChar(piece.role);
1395
+ let r = roleToChar(piece.role);
1372
1396
  if (piece.color === "white")
1373
- r2 = r2.toUpperCase();
1397
+ r = r.toUpperCase();
1374
1398
  if (piece.promoted)
1375
- r2 += "~";
1376
- return r2;
1399
+ r += "~";
1400
+ return r;
1377
1401
  };
1378
1402
  var makeBoardFen = (board) => {
1379
1403
  let fen = "";
@@ -1436,7 +1460,7 @@ var makeFen = (setup, opts) => [
1436
1460
  ...(opts === null || opts === void 0 ? void 0 : opts.epd) ? [] : [Math.max(0, Math.min(setup.halfmoves, 9999)), Math.max(1, Math.min(setup.fullmoves, 9999))]
1437
1461
  ].join(" ");
1438
1462
 
1439
- // node_modules/.pnpm/chessops@0.14.2/node_modules/chessops/dist/esm/san.js
1463
+ // node_modules/.pnpm/chessops@0.15.0/node_modules/chessops/dist/esm/san.js
1440
1464
  var makeSanWithoutSuffix = (pos, move3) => {
1441
1465
  let san = "";
1442
1466
  if (isDrop(move3)) {
@@ -1565,7 +1589,7 @@ var parseSan = (pos, san) => {
1565
1589
  };
1566
1590
  };
1567
1591
 
1568
- // node_modules/.pnpm/chessops@0.14.2/node_modules/chessops/dist/esm/variant.js
1592
+ // node_modules/.pnpm/chessops@0.15.0/node_modules/chessops/dist/esm/variant.js
1569
1593
  var Crazyhouse = class extends Position {
1570
1594
  constructor() {
1571
1595
  super("crazyhouse");
@@ -1596,12 +1620,12 @@ var Crazyhouse = class extends Position {
1596
1620
  return super.validate().chain((_) => {
1597
1621
  var _a, _b;
1598
1622
  if ((_a = this.pockets) === null || _a === void 0 ? void 0 : _a.count("king")) {
1599
- return n.err(new PositionError(IllegalSetup.Kings));
1623
+ return Result.err(new PositionError(IllegalSetup.Kings));
1600
1624
  }
1601
1625
  if ((((_b = this.pockets) === null || _b === void 0 ? void 0 : _b.size()) || 0) + this.board.occupied.size() > 64) {
1602
- return n.err(new PositionError(IllegalSetup.Variant));
1626
+ return Result.err(new PositionError(IllegalSetup.Variant));
1603
1627
  }
1604
- return n.ok(void 0);
1628
+ return Result.ok(void 0);
1605
1629
  });
1606
1630
  }
1607
1631
  hasInsufficientMaterial(color) {
@@ -1641,19 +1665,19 @@ var Atomic = class extends Position {
1641
1665
  }
1642
1666
  validate() {
1643
1667
  if (this.board.occupied.isEmpty())
1644
- return n.err(new PositionError(IllegalSetup.Empty));
1668
+ return Result.err(new PositionError(IllegalSetup.Empty));
1645
1669
  if (this.board.king.size() > 2)
1646
- return n.err(new PositionError(IllegalSetup.Kings));
1670
+ return Result.err(new PositionError(IllegalSetup.Kings));
1647
1671
  const otherKing = this.board.kingOf(opposite(this.turn));
1648
1672
  if (!defined(otherKing))
1649
- return n.err(new PositionError(IllegalSetup.Kings));
1673
+ return Result.err(new PositionError(IllegalSetup.Kings));
1650
1674
  if (this.kingAttackers(otherKing, this.turn, this.board.occupied).nonEmpty()) {
1651
- return n.err(new PositionError(IllegalSetup.OppositeCheck));
1675
+ return Result.err(new PositionError(IllegalSetup.OppositeCheck));
1652
1676
  }
1653
1677
  if (SquareSet.backranks().intersects(this.board.pawn)) {
1654
- return n.err(new PositionError(IllegalSetup.PawnsOnBackrank));
1678
+ return Result.err(new PositionError(IllegalSetup.PawnsOnBackrank));
1655
1679
  }
1656
- return n.ok(void 0);
1680
+ return Result.ok(void 0);
1657
1681
  }
1658
1682
  kingAttackers(square, attacker, occupied) {
1659
1683
  const attackerKings = this.board.pieces(attacker, "king");
@@ -1749,11 +1773,11 @@ var Antichess = class extends Position {
1749
1773
  }
1750
1774
  validate() {
1751
1775
  if (this.board.occupied.isEmpty())
1752
- return n.err(new PositionError(IllegalSetup.Empty));
1776
+ return Result.err(new PositionError(IllegalSetup.Empty));
1753
1777
  if (SquareSet.backranks().intersects(this.board.pawn)) {
1754
- return n.err(new PositionError(IllegalSetup.PawnsOnBackrank));
1778
+ return Result.err(new PositionError(IllegalSetup.PawnsOnBackrank));
1755
1779
  }
1756
- return n.ok(void 0);
1780
+ return Result.ok(void 0);
1757
1781
  }
1758
1782
  kingAttackers(_square, _attacker, _occupied) {
1759
1783
  return SquareSet.empty();
@@ -1927,7 +1951,7 @@ var RacingKings = class extends Position {
1927
1951
  }
1928
1952
  validate() {
1929
1953
  if (this.isCheck() || this.board.pawn.nonEmpty())
1930
- return n.err(new PositionError(IllegalSetup.Variant));
1954
+ return Result.err(new PositionError(IllegalSetup.Variant));
1931
1955
  return super.validate();
1932
1956
  }
1933
1957
  dests(square, ctx) {
@@ -2021,20 +2045,20 @@ var Horde = class extends Position {
2021
2045
  }
2022
2046
  validate() {
2023
2047
  if (this.board.occupied.isEmpty())
2024
- return n.err(new PositionError(IllegalSetup.Empty));
2048
+ return Result.err(new PositionError(IllegalSetup.Empty));
2025
2049
  if (this.board.king.size() !== 1)
2026
- return n.err(new PositionError(IllegalSetup.Kings));
2050
+ return Result.err(new PositionError(IllegalSetup.Kings));
2027
2051
  const otherKing = this.board.kingOf(opposite(this.turn));
2028
2052
  if (defined(otherKing) && this.kingAttackers(otherKing, this.turn, this.board.occupied).nonEmpty()) {
2029
- return n.err(new PositionError(IllegalSetup.OppositeCheck));
2053
+ return Result.err(new PositionError(IllegalSetup.OppositeCheck));
2030
2054
  }
2031
2055
  for (const color of COLORS) {
2032
2056
  const backranks = this.board.pieces(color, "king").isEmpty() ? SquareSet.backrank(opposite(color)) : SquareSet.backranks();
2033
2057
  if (this.board.pieces(color, "pawn").intersects(backranks)) {
2034
- return n.err(new PositionError(IllegalSetup.PawnsOnBackrank));
2058
+ return Result.err(new PositionError(IllegalSetup.PawnsOnBackrank));
2035
2059
  }
2036
2060
  }
2037
- return n.ok(void 0);
2061
+ return Result.ok(void 0);
2038
2062
  }
2039
2063
  hasInsufficientMaterial(color) {
2040
2064
  if (this.board.pieces(color, "king").nonEmpty())
@@ -2183,7 +2207,7 @@ var setupPosition = (rules, setup) => {
2183
2207
  }
2184
2208
  };
2185
2209
 
2186
- // node_modules/.pnpm/chessops@0.14.2/node_modules/chessops/dist/esm/pgn.js
2210
+ // node_modules/.pnpm/chessops@0.15.0/node_modules/chessops/dist/esm/pgn.js
2187
2211
  var defaultGame = (initHeaders = defaultHeaders) => ({
2188
2212
  headers: initHeaders(),
2189
2213
  moves: new Node()
@@ -2549,12 +2573,12 @@ var parseVariant = (variant) => {
2549
2573
  var startingPosition = (headers) => {
2550
2574
  const rules = parseVariant(headers.get("Variant"));
2551
2575
  if (!rules)
2552
- return n.err(new PositionError(IllegalSetup.Variant));
2576
+ return Result.err(new PositionError(IllegalSetup.Variant));
2553
2577
  const fen = headers.get("FEN");
2554
2578
  if (fen)
2555
2579
  return parseFen(fen).chain((setup) => setupPosition(rules, setup));
2556
2580
  else
2557
- return n.ok(defaultPosition(rules));
2581
+ return Result.ok(defaultPosition(rules));
2558
2582
  };
2559
2583
  function parseCommentShapeColor(str) {
2560
2584
  switch (str) {
@@ -2612,10 +2636,21 @@ var parseComment = (comment) => {
2612
2636
  };
2613
2637
 
2614
2638
  // src/translation.ts
2615
- function translate(translator) {
2616
- return (key) => translator && translator(key) || defaultTranslator(key);
2617
- }
2618
2639
  var defaultTranslator = (key) => defaultTranslations[key];
2640
+ function translate(custom) {
2641
+ return (key, ...args) => {
2642
+ const translated = custom && custom(key) || defaultTranslator(key);
2643
+ return interpolate(translated ?? key, args);
2644
+ };
2645
+ }
2646
+ var interpolate = (str, args) => {
2647
+ let result = str;
2648
+ args.forEach((arg, index) => {
2649
+ result = result.replace(`%${index + 1}$s`, arg);
2650
+ result = result.replace("%s", arg);
2651
+ });
2652
+ return result;
2653
+ };
2619
2654
  var defaultTranslations = {
2620
2655
  flipTheBoard: "Flip the board",
2621
2656
  analysisBoard: "Analysis board",
@@ -2623,7 +2658,44 @@ var defaultTranslations = {
2623
2658
  getPgn: "Get PGN",
2624
2659
  download: "Download",
2625
2660
  viewOnLichess: "View on Lichess",
2626
- viewOnSite: "View on site"
2661
+ viewOnSite: "View on site",
2662
+ menu: "Menu",
2663
+ "aria.first": "Go to first move",
2664
+ "aria.prev": "Go to previous move",
2665
+ "aria.next": "Go to next move",
2666
+ "aria.last": "Go to last move",
2667
+ "aria.gameMoves": "Game moves",
2668
+ "aria.gameResult": "Game result",
2669
+ "aria.variation": "Variation",
2670
+ "aria.navigationControls": "Game navigation controls",
2671
+ "aria.viewProfileOnLichess": "View %s's profile on Lichess",
2672
+ "aria.chessGameBetween": "Chess game between %1$s, whites, and %2$s, blacks. %3$s",
2673
+ "aria.gameInProgress": "Game in progress",
2674
+ "aria.whitesWin": "Whites win",
2675
+ "aria.blacksWin": "Blacks win",
2676
+ "aria.draw": "Draw",
2677
+ "aria.unknownPlayer": "Unknown player",
2678
+ "aria.rated": "rated %s",
2679
+ "aria.move": "Move %1$s, %2$s, %3$s",
2680
+ "aria.white": "white",
2681
+ "aria.black": "black",
2682
+ "aria.remaining": "%s remaining",
2683
+ "aria.linkOpensInNewTab": "%s, link, opens in new tab",
2684
+ "aria.accessibleChessboard": "Accessible chessboard",
2685
+ "aria.piece.king": "king",
2686
+ "aria.piece.queen": "queen",
2687
+ "aria.piece.rook": "rook",
2688
+ "aria.piece.bishop": "bishop",
2689
+ "aria.piece.knight": "knight",
2690
+ "aria.piece.pawn": "pawn",
2691
+ "aria.empty": "empty",
2692
+ "san.takes": "takes",
2693
+ "san.check": "check",
2694
+ "san.checkmate": "checkmate",
2695
+ "san.promotesTo": "promotes to",
2696
+ "san.droppedOn": "dropped on",
2697
+ "san.longCastling": "long castling",
2698
+ "san.shortCastling": "short castling"
2627
2699
  };
2628
2700
 
2629
2701
  // node_modules/.pnpm/chessground@9.2.1/node_modules/chessground/dist/types.js
@@ -2633,7 +2705,7 @@ var ranks = ["1", "2", "3", "4", "5", "6", "7", "8"];
2633
2705
 
2634
2706
  // node_modules/.pnpm/chessground@9.2.1/node_modules/chessground/dist/util.js
2635
2707
  var invRanks = [...ranks].reverse();
2636
- var allKeys = Array.prototype.concat(...files.map((c) => ranks.map((r2) => c + r2)));
2708
+ var allKeys = Array.prototype.concat(...files.map((c) => ranks.map((r) => c + r)));
2637
2709
  var pos2key = (pos) => allKeys[8 * pos[0] + pos[1]];
2638
2710
  var key2pos = (k) => [k.charCodeAt(0) - 97, k.charCodeAt(1) - 49];
2639
2711
  var uciToMove = (uci) => {
@@ -2693,15 +2765,15 @@ var translateAndScale = (el, pos, scale = 1) => {
2693
2765
  var setVisible = (el, v) => {
2694
2766
  el.style.visibility = v ? "visible" : "hidden";
2695
2767
  };
2696
- var eventPosition = (e2) => {
2768
+ var eventPosition = (e) => {
2697
2769
  var _a;
2698
- if (e2.clientX || e2.clientX === 0)
2699
- return [e2.clientX, e2.clientY];
2700
- if ((_a = e2.targetTouches) === null || _a === void 0 ? void 0 : _a[0])
2701
- return [e2.targetTouches[0].clientX, e2.targetTouches[0].clientY];
2770
+ if (e.clientX || e.clientX === 0)
2771
+ return [e.clientX, e.clientY];
2772
+ if ((_a = e.targetTouches) === null || _a === void 0 ? void 0 : _a[0])
2773
+ return [e.targetTouches[0].clientX, e.targetTouches[0].clientY];
2702
2774
  return;
2703
2775
  };
2704
- var isRightButton = (e2) => e2.button === 2;
2776
+ var isRightButton = (e) => e.button === 2;
2705
2777
  var createEl = (tagName2, className) => {
2706
2778
  const el = document.createElement(tagName2);
2707
2779
  if (className)
@@ -2771,7 +2843,7 @@ var nodeAtPathFrom = (node, path) => {
2771
2843
  const child = childById(node, path.head());
2772
2844
  return child ? nodeAtPathFrom(child, path.tail()) : void 0;
2773
2845
  };
2774
- var isMoveNode = (n2) => "data" in n2;
2846
+ var isMoveNode = (n) => "data" in n;
2775
2847
  var isMoveData = (d) => "uci" in d;
2776
2848
 
2777
2849
  // src/pgn.ts
@@ -2787,7 +2859,7 @@ var parseComments = (strings) => {
2787
2859
  const comments = strings.map(parseComment);
2788
2860
  const reduceTimes = (times) => times.reduce((last, time) => typeof time == void 0 ? last : time, void 0);
2789
2861
  return {
2790
- texts: comments.map((c) => c.text).filter((t2) => !!t2),
2862
+ texts: comments.map((c) => c.text).filter((t) => !!t),
2791
2863
  shapes: comments.flatMap((c) => c.shapes),
2792
2864
  clock: reduceTimes(comments.map((c) => c.clock)),
2793
2865
  emt: reduceTimes(comments.map((c) => c.emt))
@@ -2917,6 +2989,9 @@ var PgnViewer = class {
2917
2989
  this.toggleMenu = () => {
2918
2990
  this.pane = this.pane == "board" ? "menu" : "board";
2919
2991
  this.redraw();
2992
+ if (this.pane == "board") {
2993
+ setTimeout(() => this.menuButton?.focus(), 0);
2994
+ }
2920
2995
  };
2921
2996
  this.togglePgn = () => {
2922
2997
  this.pane = this.pane == "pgn" ? "board" : "pgn";
@@ -3002,7 +3077,7 @@ function premove(pieces, key, canCastle) {
3002
3077
  const piece = pieces.get(key);
3003
3078
  if (!piece)
3004
3079
  return [];
3005
- const pos = key2pos(key), r2 = piece.role, mobility = r2 === "pawn" ? pawn(piece.color) : r2 === "knight" ? knight : r2 === "bishop" ? bishop : r2 === "rook" ? rook : r2 === "queen" ? queen : king(piece.color, rookFilesOf(pieces, piece.color), canCastle);
3080
+ const pos = key2pos(key), r = piece.role, mobility = r === "pawn" ? pawn(piece.color) : r === "knight" ? knight : r === "bishop" ? bishop : r === "rook" ? rook : r === "queen" ? queen : king(piece.color, rookFilesOf(pieces, piece.color), canCastle);
3006
3081
  return allPos.filter((pos2) => (pos[0] !== pos2[0] || pos[1] !== pos2[1]) && mobility(pos[0], pos[1], pos2[0], pos2[1])).map(pos2key);
3007
3082
  }
3008
3083
 
@@ -3517,23 +3592,23 @@ function animate(mutation, state) {
3517
3592
  }
3518
3593
  return result;
3519
3594
  }
3520
- var easing = (t2) => t2 < 0.5 ? 4 * t2 * t2 * t2 : (t2 - 1) * (2 * t2 - 2) * (2 * t2 - 2) + 1;
3595
+ var easing = (t) => t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1;
3521
3596
 
3522
3597
  // node_modules/.pnpm/chessground@9.2.1/node_modules/chessground/dist/draw.js
3523
3598
  var brushes = ["green", "red", "blue", "yellow"];
3524
- function start(state, e2) {
3525
- if (e2.touches && e2.touches.length > 1)
3599
+ function start(state, e) {
3600
+ if (e.touches && e.touches.length > 1)
3526
3601
  return;
3527
- e2.stopPropagation();
3528
- e2.preventDefault();
3529
- e2.ctrlKey ? unselect(state) : cancelMove(state);
3530
- const pos = eventPosition(e2), orig = getKeyAtDomPos(pos, whitePov(state), state.dom.bounds());
3602
+ e.stopPropagation();
3603
+ e.preventDefault();
3604
+ e.ctrlKey ? unselect(state) : cancelMove(state);
3605
+ const pos = eventPosition(e), orig = getKeyAtDomPos(pos, whitePov(state), state.dom.bounds());
3531
3606
  if (!orig)
3532
3607
  return;
3533
3608
  state.drawable.current = {
3534
3609
  orig,
3535
3610
  pos,
3536
- brush: eventBrush(e2),
3611
+ brush: eventBrush(e),
3537
3612
  snapToValidMove: state.drawable.defaultSnapToValidMove
3538
3613
  };
3539
3614
  processDraw(state);
@@ -3556,9 +3631,9 @@ function processDraw(state) {
3556
3631
  }
3557
3632
  });
3558
3633
  }
3559
- function move(state, e2) {
3634
+ function move(state, e) {
3560
3635
  if (state.drawable.current)
3561
- state.drawable.current.pos = eventPosition(e2);
3636
+ state.drawable.current.pos = eventPosition(e);
3562
3637
  }
3563
3638
  function end(state) {
3564
3639
  const cur = state.drawable.current;
@@ -3581,10 +3656,10 @@ function clear(state) {
3581
3656
  onChange(state.drawable);
3582
3657
  }
3583
3658
  }
3584
- function eventBrush(e2) {
3659
+ function eventBrush(e) {
3585
3660
  var _a;
3586
- const modA = (e2.shiftKey || e2.ctrlKey) && isRightButton(e2);
3587
- const modB = e2.altKey || e2.metaKey || ((_a = e2.getModifierState) === null || _a === void 0 ? void 0 : _a.call(e2, "AltGraph"));
3661
+ const modA = (e.shiftKey || e.ctrlKey) && isRightButton(e);
3662
+ const modB = e.altKey || e.metaKey || ((_a = e.getModifierState) === null || _a === void 0 ? void 0 : _a.call(e, "AltGraph"));
3588
3663
  return brushes[(modA ? 1 : 0) + (modB ? 2 : 0)];
3589
3664
  }
3590
3665
  function addShape(drawable, cur) {
@@ -3606,27 +3681,27 @@ function onChange(drawable) {
3606
3681
  }
3607
3682
 
3608
3683
  // node_modules/.pnpm/chessground@9.2.1/node_modules/chessground/dist/drag.js
3609
- function start2(s, e2) {
3610
- if (!(s.trustAllEvents || e2.isTrusted))
3684
+ function start2(s, e) {
3685
+ if (!(s.trustAllEvents || e.isTrusted))
3611
3686
  return;
3612
- if (e2.buttons !== void 0 && e2.buttons > 1)
3687
+ if (e.buttons !== void 0 && e.buttons > 1)
3613
3688
  return;
3614
- if (e2.touches && e2.touches.length > 1)
3689
+ if (e.touches && e.touches.length > 1)
3615
3690
  return;
3616
- const bounds = s.dom.bounds(), position = eventPosition(e2), orig = getKeyAtDomPos(position, whitePov(s), bounds);
3691
+ const bounds = s.dom.bounds(), position = eventPosition(e), orig = getKeyAtDomPos(position, whitePov(s), bounds);
3617
3692
  if (!orig)
3618
3693
  return;
3619
3694
  const piece = s.pieces.get(orig);
3620
3695
  const previouslySelected = s.selected;
3621
3696
  if (!previouslySelected && s.drawable.enabled && (s.drawable.eraseOnClick || !piece || piece.color !== s.turnColor))
3622
3697
  clear(s);
3623
- if (e2.cancelable !== false && (!e2.touches || s.blockTouchScroll || piece || previouslySelected || pieceCloseTo(s, position)))
3624
- e2.preventDefault();
3625
- else if (e2.touches)
3698
+ if (e.cancelable !== false && (!e.touches || s.blockTouchScroll || piece || previouslySelected || pieceCloseTo(s, position)))
3699
+ e.preventDefault();
3700
+ else if (e.touches)
3626
3701
  return;
3627
3702
  const hadPremove = !!s.premovable.current;
3628
3703
  const hadPredrop = !!s.predroppable.current;
3629
- s.stats.ctrlKey = e2.ctrlKey;
3704
+ s.stats.ctrlKey = e.ctrlKey;
3630
3705
  if (s.selected && canMove(s, s.selected, orig)) {
3631
3706
  anim((state) => selectSquare(state, orig), s);
3632
3707
  } else {
@@ -3643,7 +3718,7 @@ function start2(s, e2) {
3643
3718
  started: s.draggable.autoDistance && s.stats.dragged,
3644
3719
  element,
3645
3720
  previouslySelected,
3646
- originTarget: e2.target,
3721
+ originTarget: e.target,
3647
3722
  keyHasChanged: false
3648
3723
  };
3649
3724
  element.cgDragging = true;
@@ -3672,11 +3747,11 @@ function pieceCloseTo(s, pos) {
3672
3747
  }
3673
3748
  return false;
3674
3749
  }
3675
- function dragNewPiece(s, piece, e2, force) {
3750
+ function dragNewPiece(s, piece, e, force) {
3676
3751
  const key = "a0";
3677
3752
  s.pieces.set(key, piece);
3678
3753
  s.dom.redraw();
3679
- const position = eventPosition(e2);
3754
+ const position = eventPosition(e);
3680
3755
  s.draggable.current = {
3681
3756
  orig: key,
3682
3757
  piece,
@@ -3684,7 +3759,7 @@ function dragNewPiece(s, piece, e2, force) {
3684
3759
  pos: position,
3685
3760
  started: true,
3686
3761
  element: () => pieceElementByKey(s, key),
3687
- originTarget: e2.target,
3762
+ originTarget: e.target,
3688
3763
  newPiece: true,
3689
3764
  force: !!force,
3690
3765
  keyHasChanged: false
@@ -3725,30 +3800,30 @@ function processDrag(s) {
3725
3800
  processDrag(s);
3726
3801
  });
3727
3802
  }
3728
- function move2(s, e2) {
3729
- if (s.draggable.current && (!e2.touches || e2.touches.length < 2)) {
3730
- s.draggable.current.pos = eventPosition(e2);
3803
+ function move2(s, e) {
3804
+ if (s.draggable.current && (!e.touches || e.touches.length < 2)) {
3805
+ s.draggable.current.pos = eventPosition(e);
3731
3806
  }
3732
3807
  }
3733
- function end2(s, e2) {
3808
+ function end2(s, e) {
3734
3809
  const cur = s.draggable.current;
3735
3810
  if (!cur)
3736
3811
  return;
3737
- if (e2.type === "touchend" && e2.cancelable !== false)
3738
- e2.preventDefault();
3739
- if (e2.type === "touchend" && cur.originTarget !== e2.target && !cur.newPiece) {
3812
+ if (e.type === "touchend" && e.cancelable !== false)
3813
+ e.preventDefault();
3814
+ if (e.type === "touchend" && cur.originTarget !== e.target && !cur.newPiece) {
3740
3815
  s.draggable.current = void 0;
3741
3816
  return;
3742
3817
  }
3743
3818
  unsetPremove(s);
3744
3819
  unsetPredrop(s);
3745
- const eventPos = eventPosition(e2) || cur.pos;
3820
+ const eventPos = eventPosition(e) || cur.pos;
3746
3821
  const dest = getKeyAtDomPos(eventPos, whitePov(s), s.dom.bounds());
3747
3822
  if (dest && cur.started && cur.orig !== dest) {
3748
3823
  if (cur.newPiece)
3749
3824
  dropNewPiece(s, cur.orig, dest, cur.force);
3750
3825
  else {
3751
- s.stats.ctrlKey = e2.ctrlKey;
3826
+ s.stats.ctrlKey = e.ctrlKey;
3752
3827
  if (userMove(s, cur.orig, dest))
3753
3828
  s.stats.dragged = true;
3754
3829
  }
@@ -3778,9 +3853,9 @@ function cancel2(s) {
3778
3853
  }
3779
3854
  }
3780
3855
  function removeDragElements(s) {
3781
- const e2 = s.dom.elements;
3782
- if (e2.ghost)
3783
- setVisible(e2.ghost, false);
3856
+ const e = s.dom.elements;
3857
+ if (e.ghost)
3858
+ setVisible(e.ghost, false);
3784
3859
  }
3785
3860
  function pieceElementByKey(s, key) {
3786
3861
  let el = s.dom.elements.board.firstChild;
@@ -4342,7 +4417,7 @@ function renderWrap(element, s) {
4342
4417
  const ranksPositionClass = s.ranksPosition === "left" ? " left" : "";
4343
4418
  if (s.coordinatesOnSquares) {
4344
4419
  const rankN = s.orientation === "white" ? (i) => i + 1 : (i) => 8 - i;
4345
- files.forEach((f, i) => container.appendChild(renderCoords(ranks.map((r2) => f + r2), "squares rank" + rankN(i) + orientClass + ranksPositionClass)));
4420
+ files.forEach((f, i) => container.appendChild(renderCoords(ranks.map((r) => f + r), "squares rank" + rankN(i) + orientClass + ranksPositionClass)));
4346
4421
  } else {
4347
4422
  container.appendChild(renderCoords(ranks, "ranks" + orientClass + ranksPositionClass));
4348
4423
  container.appendChild(renderCoords(files, "files" + orientClass));
@@ -4376,7 +4451,7 @@ function renderCoords(elems, className) {
4376
4451
  }
4377
4452
 
4378
4453
  // node_modules/.pnpm/chessground@9.2.1/node_modules/chessground/dist/drop.js
4379
- function drop(s, e2) {
4454
+ function drop(s, e) {
4380
4455
  if (!s.dropmode.active)
4381
4456
  return;
4382
4457
  unsetPremove(s);
@@ -4384,7 +4459,7 @@ function drop(s, e2) {
4384
4459
  const piece = s.dropmode.piece;
4385
4460
  if (piece) {
4386
4461
  s.pieces.set("a0", piece);
4387
- const position = eventPosition(e2);
4462
+ const position = eventPosition(e);
4388
4463
  const dest = position && getKeyAtDomPos(position, whitePov(s), s.dom.bounds());
4389
4464
  if (dest)
4390
4465
  dropNewPiece(s, "a0", dest);
@@ -4398,7 +4473,7 @@ function bindBoard(s, onResize) {
4398
4473
  if ("ResizeObserver" in window)
4399
4474
  new ResizeObserver(onResize).observe(s.dom.elements.wrap);
4400
4475
  if (s.disableContextMenu || s.drawable.enabled) {
4401
- boardEl.addEventListener("contextmenu", (e2) => e2.preventDefault());
4476
+ boardEl.addEventListener("contextmenu", (e) => e.preventDefault());
4402
4477
  }
4403
4478
  if (s.viewOnly)
4404
4479
  return;
@@ -4431,27 +4506,27 @@ function unbindable(el, eventName, callback, options) {
4431
4506
  el.addEventListener(eventName, callback, options);
4432
4507
  return () => el.removeEventListener(eventName, callback, options);
4433
4508
  }
4434
- var startDragOrDraw = (s) => (e2) => {
4509
+ var startDragOrDraw = (s) => (e) => {
4435
4510
  if (s.draggable.current)
4436
4511
  cancel2(s);
4437
4512
  else if (s.drawable.current)
4438
4513
  cancel(s);
4439
- else if (e2.shiftKey || isRightButton(e2)) {
4514
+ else if (e.shiftKey || isRightButton(e)) {
4440
4515
  if (s.drawable.enabled)
4441
- start(s, e2);
4516
+ start(s, e);
4442
4517
  } else if (!s.viewOnly) {
4443
4518
  if (s.dropmode.active)
4444
- drop(s, e2);
4519
+ drop(s, e);
4445
4520
  else
4446
- start2(s, e2);
4521
+ start2(s, e);
4447
4522
  }
4448
4523
  };
4449
- var dragOrDraw = (s, withDrag, withDraw) => (e2) => {
4524
+ var dragOrDraw = (s, withDrag, withDraw) => (e) => {
4450
4525
  if (s.drawable.current) {
4451
4526
  if (s.drawable.enabled)
4452
- withDraw(s, e2);
4527
+ withDraw(s, e);
4453
4528
  } else if (!s.viewOnly)
4454
- withDrag(s, e2);
4529
+ withDrag(s, e);
4455
4530
  };
4456
4531
 
4457
4532
  // node_modules/.pnpm/chessground@9.2.1/node_modules/chessground/dist/render.js
@@ -4772,7 +4847,7 @@ function debounceRedraw(redrawNow) {
4772
4847
  };
4773
4848
  }
4774
4849
 
4775
- // node_modules/.pnpm/snabbdom@3.6.2/node_modules/snabbdom/build/htmldomapi.js
4850
+ // node_modules/.pnpm/snabbdom@3.5.1/node_modules/snabbdom/build/htmldomapi.js
4776
4851
  function createElement2(tagName2, options) {
4777
4852
  return document.createElement(tagName2, options);
4778
4853
  }
@@ -4887,19 +4962,19 @@ var htmlDomApi = {
4887
4962
  isDocumentFragment
4888
4963
  };
4889
4964
 
4890
- // node_modules/.pnpm/snabbdom@3.6.2/node_modules/snabbdom/build/vnode.js
4965
+ // node_modules/.pnpm/snabbdom@3.5.1/node_modules/snabbdom/build/vnode.js
4891
4966
  function vnode(sel, data, children, text, elm) {
4892
4967
  const key = data === void 0 ? void 0 : data.key;
4893
4968
  return { sel, data, children, text, elm, key };
4894
4969
  }
4895
4970
 
4896
- // node_modules/.pnpm/snabbdom@3.6.2/node_modules/snabbdom/build/is.js
4971
+ // node_modules/.pnpm/snabbdom@3.5.1/node_modules/snabbdom/build/is.js
4897
4972
  var array = Array.isArray;
4898
4973
  function primitive(s) {
4899
4974
  return typeof s === "string" || typeof s === "number" || s instanceof String || s instanceof Number;
4900
4975
  }
4901
4976
 
4902
- // node_modules/.pnpm/snabbdom@3.6.2/node_modules/snabbdom/build/init.js
4977
+ // node_modules/.pnpm/snabbdom@3.5.1/node_modules/snabbdom/build/init.js
4903
4978
  function isUndef(s) {
4904
4979
  return s === void 0;
4905
4980
  }
@@ -4974,9 +5049,7 @@ function init(modules, domApi, options) {
4974
5049
  return function rmCb() {
4975
5050
  if (--listeners === 0) {
4976
5051
  const parent = api.parentNode(childElm);
4977
- if (parent !== null) {
4978
- api.removeChild(parent, childElm);
4979
- }
5052
+ api.removeChild(parent, childElm);
4980
5053
  }
4981
5054
  };
4982
5055
  }
@@ -4998,8 +5071,6 @@ function init(modules, domApi, options) {
4998
5071
  vnode2.text = "";
4999
5072
  }
5000
5073
  vnode2.elm = api.createComment(vnode2.text);
5001
- } else if (sel === "") {
5002
- vnode2.elm = api.createTextNode(vnode2.text);
5003
5074
  } else if (sel !== void 0) {
5004
5075
  const hashIdx = sel.indexOf("#");
5005
5076
  const dotIdx = sel.indexOf(".", hashIdx);
@@ -5013,9 +5084,6 @@ function init(modules, domApi, options) {
5013
5084
  elm.setAttribute("class", sel.slice(dot + 1).replace(/\./g, " "));
5014
5085
  for (i = 0; i < cbs.create.length; ++i)
5015
5086
  cbs.create[i](emptyNode, vnode2);
5016
- if (primitive(vnode2.text) && (!array(children) || children.length === 0)) {
5017
- api.appendChild(elm, api.createTextNode(vnode2.text));
5018
- }
5019
5087
  if (array(children)) {
5020
5088
  for (i = 0; i < children.length; ++i) {
5021
5089
  const ch = children[i];
@@ -5023,6 +5091,8 @@ function init(modules, domApi, options) {
5023
5091
  api.appendChild(elm, createElm(ch, insertedVnodeQueue));
5024
5092
  }
5025
5093
  }
5094
+ } else if (primitive(vnode2.text)) {
5095
+ api.appendChild(elm, api.createTextNode(vnode2.text));
5026
5096
  }
5027
5097
  const hook = vnode2.data.hook;
5028
5098
  if (isDef(hook)) {
@@ -5146,10 +5216,6 @@ function init(modules, domApi, options) {
5146
5216
  idxInOld = oldKeyToIdx[newStartVnode.key];
5147
5217
  if (isUndef(idxInOld)) {
5148
5218
  api.insertBefore(parentElm, createElm(newStartVnode, insertedVnodeQueue), oldStartVnode.elm);
5149
- newStartVnode = newCh[++newStartIdx];
5150
- } else if (isUndef(oldKeyToIdx[newEndVnode.key])) {
5151
- api.insertBefore(parentElm, createElm(newEndVnode, insertedVnodeQueue), api.nextSibling(oldEndVnode.elm));
5152
- newEndVnode = newCh[--newEndIdx];
5153
5219
  } else {
5154
5220
  elmToMove = oldCh[idxInOld];
5155
5221
  if (elmToMove.sel !== newStartVnode.sel) {
@@ -5159,8 +5225,8 @@ function init(modules, domApi, options) {
5159
5225
  oldCh[idxInOld] = void 0;
5160
5226
  api.insertBefore(parentElm, elmToMove.elm, oldStartVnode.elm);
5161
5227
  }
5162
- newStartVnode = newCh[++newStartIdx];
5163
5228
  }
5229
+ newStartVnode = newCh[++newStartIdx];
5164
5230
  }
5165
5231
  }
5166
5232
  if (newStartIdx <= newEndIdx) {
@@ -5238,7 +5304,7 @@ function init(modules, domApi, options) {
5238
5304
  };
5239
5305
  }
5240
5306
 
5241
- // node_modules/.pnpm/snabbdom@3.6.2/node_modules/snabbdom/build/h.js
5307
+ // node_modules/.pnpm/snabbdom@3.5.1/node_modules/snabbdom/build/h.js
5242
5308
  function addNS(data, children, sel) {
5243
5309
  data.ns = "http://www.w3.org/2000/svg";
5244
5310
  if (sel !== "foreignObject" && children !== void 0) {
@@ -5286,19 +5352,17 @@ function h(sel, b, c) {
5286
5352
  children[i] = vnode(void 0, void 0, void 0, children[i], void 0);
5287
5353
  }
5288
5354
  }
5289
- if (sel.startsWith("svg") && (sel.length === 3 || sel[3] === "." || sel[3] === "#")) {
5355
+ if (sel[0] === "s" && sel[1] === "v" && sel[2] === "g" && (sel.length === 3 || sel[3] === "." || sel[3] === "#")) {
5290
5356
  addNS(data, children, sel);
5291
5357
  }
5292
5358
  return vnode(sel, data, children, text, void 0);
5293
5359
  }
5294
5360
 
5295
- // node_modules/.pnpm/snabbdom@3.6.2/node_modules/snabbdom/build/modules/attributes.js
5361
+ // node_modules/.pnpm/snabbdom@3.5.1/node_modules/snabbdom/build/modules/attributes.js
5296
5362
  var xlinkNS = "http://www.w3.org/1999/xlink";
5297
- var xmlnsNS = "http://www.w3.org/2000/xmlns/";
5298
5363
  var xmlNS = "http://www.w3.org/XML/1998/namespace";
5299
5364
  var colonChar = 58;
5300
5365
  var xChar = 120;
5301
- var mChar = 109;
5302
5366
  function updateAttrs(oldVnode, vnode2) {
5303
5367
  let key;
5304
5368
  const elm = vnode2.elm;
@@ -5324,7 +5388,7 @@ function updateAttrs(oldVnode, vnode2) {
5324
5388
  } else if (key.charCodeAt(3) === colonChar) {
5325
5389
  elm.setAttributeNS(xmlNS, key, cur);
5326
5390
  } else if (key.charCodeAt(5) === colonChar) {
5327
- key.charCodeAt(1) === mChar ? elm.setAttributeNS(xmlnsNS, key, cur) : elm.setAttributeNS(xlinkNS, key, cur);
5391
+ elm.setAttributeNS(xlinkNS, key, cur);
5328
5392
  } else {
5329
5393
  elm.setAttribute(key, cur);
5330
5394
  }
@@ -5342,7 +5406,7 @@ var attributesModule = {
5342
5406
  update: updateAttrs
5343
5407
  };
5344
5408
 
5345
- // node_modules/.pnpm/snabbdom@3.6.2/node_modules/snabbdom/build/modules/class.js
5409
+ // node_modules/.pnpm/snabbdom@3.5.1/node_modules/snabbdom/build/modules/class.js
5346
5410
  function updateClass(oldVnode, vnode2) {
5347
5411
  let cur;
5348
5412
  let name;
@@ -5369,144 +5433,6 @@ function updateClass(oldVnode, vnode2) {
5369
5433
  }
5370
5434
  var classModule = { create: updateClass, update: updateClass };
5371
5435
 
5372
- // src/view/util.ts
5373
- function bindMobileMousedown(el, f, redraw) {
5374
- for (const mousedownEvent of ["touchstart", "mousedown"]) {
5375
- el.addEventListener(
5376
- mousedownEvent,
5377
- (e2) => {
5378
- f(e2);
5379
- e2.preventDefault();
5380
- if (redraw) redraw();
5381
- },
5382
- { passive: false }
5383
- );
5384
- }
5385
- }
5386
- var bind = (eventName, f, redraw, passive = true) => onInsert(
5387
- (el) => el.addEventListener(
5388
- eventName,
5389
- (e2) => {
5390
- const res = f(e2);
5391
- if (res === false) e2.preventDefault();
5392
- redraw?.();
5393
- return res;
5394
- },
5395
- { passive }
5396
- )
5397
- );
5398
- function onInsert(f) {
5399
- return {
5400
- insert: (vnode2) => f(vnode2.elm)
5401
- };
5402
- }
5403
-
5404
- // src/events.ts
5405
- function stepwiseScroll(inner) {
5406
- let scrollTotal = 0;
5407
- return (e2) => {
5408
- scrollTotal += e2.deltaY * (e2.deltaMode ? 40 : 1);
5409
- if (Math.abs(scrollTotal) >= 4) {
5410
- inner(e2, true);
5411
- scrollTotal = 0;
5412
- } else {
5413
- inner(e2, false);
5414
- }
5415
- };
5416
- }
5417
- function eventRepeater(action, e2) {
5418
- const repeat = () => {
5419
- action();
5420
- delay = Math.max(100, delay - delay / 15);
5421
- timeout = setTimeout(repeat, delay);
5422
- };
5423
- let delay = 350;
5424
- let timeout = setTimeout(repeat, 500);
5425
- action();
5426
- const eventName = e2.type == "touchstart" ? "touchend" : "mouseup";
5427
- document.addEventListener(eventName, () => clearTimeout(timeout), { once: true });
5428
- }
5429
- var suppressKeyNavOn = (e2) => e2.altKey || e2.ctrlKey || e2.shiftKey || e2.metaKey || document.activeElement instanceof HTMLInputElement || document.activeElement instanceof HTMLTextAreaElement;
5430
- var onKeyDown = (ctrl) => (e2) => {
5431
- if (suppressKeyNavOn(e2)) return;
5432
- else if (e2.key == "ArrowLeft") ctrl.goTo("prev");
5433
- else if (e2.key == "ArrowRight") ctrl.goTo("next");
5434
- else if (e2.key == "f") ctrl.flip();
5435
- };
5436
-
5437
- // src/view/menu.ts
5438
- var renderMenu = (ctrl) => h("div.lpv__menu.lpv__pane", [
5439
- h(
5440
- "button.lpv__menu__entry.lpv__menu__flip.lpv__fbt",
5441
- {
5442
- hook: bind("click", ctrl.flip)
5443
- },
5444
- ctrl.translate("flipTheBoard")
5445
- ),
5446
- ctrl.opts.menu.analysisBoard?.enabled ? h(
5447
- "a.lpv__menu__entry.lpv__menu__analysis.lpv__fbt",
5448
- {
5449
- attrs: {
5450
- href: ctrl.analysisUrl(),
5451
- target: "_blank"
5452
- }
5453
- },
5454
- ctrl.translate("analysisBoard")
5455
- ) : void 0,
5456
- ctrl.opts.menu.practiceWithComputer?.enabled ? h(
5457
- "a.lpv__menu__entry.lpv__menu__practice.lpv__fbt",
5458
- {
5459
- attrs: {
5460
- href: ctrl.practiceUrl(),
5461
- target: "_blank"
5462
- }
5463
- },
5464
- ctrl.translate("practiceWithComputer")
5465
- ) : void 0,
5466
- ctrl.opts.menu.getPgn.enabled ? h(
5467
- "button.lpv__menu__entry.lpv__menu__pgn.lpv__fbt",
5468
- {
5469
- hook: bind("click", ctrl.togglePgn)
5470
- },
5471
- ctrl.translate("getPgn")
5472
- ) : void 0,
5473
- renderExternalLink(ctrl)
5474
- ]);
5475
- var renderExternalLink = (ctrl) => {
5476
- const link = ctrl.game.metadata.externalLink;
5477
- return link && h(
5478
- "a.lpv__menu__entry.lpv__fbt",
5479
- {
5480
- attrs: {
5481
- href: link,
5482
- target: "_blank"
5483
- }
5484
- },
5485
- ctrl.translate(ctrl.game.metadata.isLichess ? "viewOnLichess" : "viewOnSite")
5486
- );
5487
- };
5488
- var renderControls = (ctrl) => h("div.lpv__controls", [
5489
- ctrl.pane == "board" ? void 0 : dirButton(ctrl, "first", "step-backward"),
5490
- dirButton(ctrl, "prev", "left-open"),
5491
- h(
5492
- "button.lpv__fbt.lpv__controls__menu.lpv__icon",
5493
- {
5494
- class: {
5495
- active: ctrl.pane != "board",
5496
- "lpv__icon-ellipsis-vert": ctrl.pane == "board"
5497
- },
5498
- hook: bind("click", ctrl.toggleMenu)
5499
- },
5500
- ctrl.pane == "board" ? void 0 : "X"
5501
- ),
5502
- dirButton(ctrl, "next", "right-open"),
5503
- ctrl.pane == "board" ? void 0 : dirButton(ctrl, "last", "step-forward")
5504
- ]);
5505
- var dirButton = (ctrl, to, icon) => h(`button.lpv__controls__goto.lpv__controls__goto--${to}.lpv__fbt.lpv__icon.lpv__icon-${icon}`, {
5506
- class: { disabled: ctrl.pane == "board" && !ctrl.canGoTo(to) },
5507
- hook: onInsert((el) => bindMobileMousedown(el, (e2) => eventRepeater(() => ctrl.goTo(to), e2)))
5508
- });
5509
-
5510
5436
  // src/view/glyph.ts
5511
5437
  var renderNag = (nag) => {
5512
5438
  const glyph = glyphs[nag];
@@ -5611,19 +5537,326 @@ var glyphs = {
5611
5537
  }
5612
5538
  };
5613
5539
 
5540
+ // src/view/util.ts
5541
+ function bindMobileMousedown(el, f, redraw) {
5542
+ for (const mousedownEvent of ["touchstart", "mousedown"]) {
5543
+ el.addEventListener(
5544
+ mousedownEvent,
5545
+ (e) => {
5546
+ f(e);
5547
+ e.preventDefault();
5548
+ if (redraw) redraw();
5549
+ },
5550
+ { passive: false }
5551
+ );
5552
+ }
5553
+ }
5554
+ var bind = (eventName, f, redraw, passive = true) => onInsert(
5555
+ (el) => el.addEventListener(
5556
+ eventName,
5557
+ (e) => {
5558
+ const res = f(e);
5559
+ if (res === false) e.preventDefault();
5560
+ redraw?.();
5561
+ return res;
5562
+ },
5563
+ { passive }
5564
+ )
5565
+ );
5566
+ function onInsert(f) {
5567
+ return {
5568
+ insert: (vnode2) => f(vnode2.elm)
5569
+ };
5570
+ }
5571
+ var clockContent = (seconds) => {
5572
+ if (!seconds && seconds !== 0) return ["-"];
5573
+ const date = new Date(seconds * 1e3), sep = ":", baseStr = pad2(date.getUTCMinutes()) + sep + pad2(date.getUTCSeconds());
5574
+ return seconds >= 3600 ? [Math.floor(seconds / 3600) + sep + baseStr] : [baseStr];
5575
+ };
5576
+ var pad2 = (num) => (num < 10 ? "0" : "") + num;
5577
+ var formatSquareForScreenReader = (translate3, file, rank, piece) => {
5578
+ const square = `${file.toUpperCase()}${rank}`;
5579
+ if (!piece) return `${square} ${translate3("aria.empty")}`;
5580
+ const pieceName = translate3(`aria.piece.${piece.role}`);
5581
+ return `${square} ${translate3(`aria.${piece.color}`)} ${pieceName}`;
5582
+ };
5583
+ var formatMoveForScreenReader = (san, nags, translate3) => {
5584
+ let formatted = translate3 ? transSanToWords(san, translate3) : san;
5585
+ if (nags && nags.length > 0) {
5586
+ const annotations = nags.map((nag) => glyphs[nag]?.name).filter((name) => name).join(", ");
5587
+ if (annotations) {
5588
+ formatted += `, ${annotations}`;
5589
+ }
5590
+ }
5591
+ return formatted;
5592
+ };
5593
+ var transSanToWords = (san, translate3) => san.split("").map((c) => {
5594
+ if (c === "x") return translate3("san.takes");
5595
+ if (c === "+") return translate3("san.check");
5596
+ if (c === "#") return translate3("san.checkmate");
5597
+ if (c === "=") return translate3("san.promotesTo");
5598
+ if (c === "@") return translate3("san.droppedOn");
5599
+ const code = c.charCodeAt(0);
5600
+ if (code > 48 && code < 58) return c;
5601
+ if (code > 96 && code < 105) return c.toUpperCase();
5602
+ if (c === "K") return translate3("aria.piece.king");
5603
+ if (c === "Q") return translate3("aria.piece.queen");
5604
+ if (c === "R") return translate3("aria.piece.rook");
5605
+ if (c === "B") return translate3("aria.piece.bishop");
5606
+ if (c === "N") return translate3("aria.piece.knight");
5607
+ if (c === "O") return "O";
5608
+ return c;
5609
+ }).join(" ").replace("O - O - O", translate3("san.longCastling")).replace("O - O", translate3("san.shortCastling"));
5610
+
5611
+ // src/events.ts
5612
+ function stepwiseScroll(inner) {
5613
+ let scrollTotal = 0;
5614
+ return (e) => {
5615
+ scrollTotal += e.deltaY * (e.deltaMode ? 40 : 1);
5616
+ if (Math.abs(scrollTotal) >= 4) {
5617
+ inner(e, true);
5618
+ scrollTotal = 0;
5619
+ } else {
5620
+ inner(e, false);
5621
+ }
5622
+ };
5623
+ }
5624
+ function eventRepeater(action, e) {
5625
+ const repeat = () => {
5626
+ action();
5627
+ delay = Math.max(100, delay - delay / 15);
5628
+ timeout = setTimeout(repeat, delay);
5629
+ };
5630
+ let delay = 350;
5631
+ let timeout = setTimeout(repeat, 500);
5632
+ action();
5633
+ const eventName = e.type == "touchstart" ? "touchend" : "mouseup";
5634
+ document.addEventListener(eventName, () => clearTimeout(timeout), { once: true });
5635
+ }
5636
+ var suppressKeyNavOn = (e) => e.altKey || e.ctrlKey || e.shiftKey || e.metaKey || document.activeElement instanceof HTMLInputElement || document.activeElement instanceof HTMLTextAreaElement;
5637
+ var onKeyDown = (ctrl) => (e) => {
5638
+ if (suppressKeyNavOn(e)) return;
5639
+ else if (e.key == "ArrowLeft") ctrl.goTo("prev");
5640
+ else if (e.key == "ArrowRight") ctrl.goTo("next");
5641
+ else if (e.key == "f") ctrl.flip();
5642
+ };
5643
+
5644
+ // src/view/menu.ts
5645
+ var renderMenu = (ctrl) => h(
5646
+ "div.lpv__menu.lpv__pane",
5647
+ {
5648
+ attrs: {
5649
+ role: "menu",
5650
+ "aria-label": ctrl.translate("menu") ?? "Menu"
5651
+ },
5652
+ hook: {
5653
+ insert: (vnode2) => {
5654
+ const menuEl = vnode2.elm;
5655
+ const firstItem = menuEl.querySelector('[role="menuitem"]');
5656
+ firstItem?.focus();
5657
+ setupMenuKeyboard(ctrl, menuEl);
5658
+ }
5659
+ }
5660
+ },
5661
+ [
5662
+ h(
5663
+ "button.lpv__menu__entry.lpv__menu__flip.lpv__fbt",
5664
+ {
5665
+ attrs: { role: "menuitem" },
5666
+ hook: bind("click", ctrl.flip)
5667
+ },
5668
+ ctrl.translate("flipTheBoard")
5669
+ ),
5670
+ ctrl.opts.menu.analysisBoard?.enabled ? h(
5671
+ "a.lpv__menu__entry.lpv__menu__analysis.lpv__fbt",
5672
+ {
5673
+ attrs: {
5674
+ role: "menuitem",
5675
+ href: ctrl.analysisUrl(),
5676
+ target: "_blank",
5677
+ "aria-label": ctrl.translate("aria.linkOpensInNewTab", ctrl.translate("analysisBoard"))
5678
+ }
5679
+ },
5680
+ ctrl.translate("analysisBoard")
5681
+ ) : void 0,
5682
+ ctrl.opts.menu.practiceWithComputer?.enabled ? h(
5683
+ "a.lpv__menu__entry.lpv__menu__practice.lpv__fbt",
5684
+ {
5685
+ attrs: {
5686
+ role: "menuitem",
5687
+ href: ctrl.practiceUrl(),
5688
+ target: "_blank",
5689
+ "aria-label": ctrl.translate(
5690
+ "aria.linkOpensInNewTab",
5691
+ ctrl.translate("practiceWithComputer")
5692
+ )
5693
+ }
5694
+ },
5695
+ ctrl.translate("practiceWithComputer")
5696
+ ) : void 0,
5697
+ ctrl.opts.menu.getPgn.enabled ? h(
5698
+ "button.lpv__menu__entry.lpv__menu__pgn.lpv__fbt",
5699
+ {
5700
+ attrs: { role: "menuitem" },
5701
+ hook: bind("click", ctrl.togglePgn)
5702
+ },
5703
+ ctrl.translate("getPgn")
5704
+ ) : void 0,
5705
+ renderExternalLink(ctrl)
5706
+ ]
5707
+ );
5708
+ var renderExternalLink = (ctrl) => {
5709
+ const link = ctrl.game.metadata.externalLink;
5710
+ const linkText = ctrl.translate(ctrl.game.metadata.isLichess ? "viewOnLichess" : "viewOnSite");
5711
+ return link && h(
5712
+ "a.lpv__menu__entry.lpv__fbt",
5713
+ {
5714
+ attrs: {
5715
+ role: "menuitem",
5716
+ href: link,
5717
+ target: "_blank",
5718
+ "aria-label": ctrl.translate("aria.linkOpensInNewTab", linkText)
5719
+ }
5720
+ },
5721
+ linkText
5722
+ );
5723
+ };
5724
+ var renderControls = (ctrl) => h(
5725
+ "div.lpv__controls",
5726
+ {
5727
+ attrs: {
5728
+ role: "navigation",
5729
+ "aria-label": ctrl.translate("aria.navigationControls")
5730
+ }
5731
+ },
5732
+ [
5733
+ ctrl.pane == "board" ? void 0 : dirButton(ctrl, "first", "step-backward"),
5734
+ dirButton(ctrl, "prev", "left-open"),
5735
+ h(
5736
+ "button.lpv__fbt.lpv__controls__menu.lpv__icon",
5737
+ {
5738
+ class: {
5739
+ active: ctrl.pane != "board",
5740
+ "lpv__icon-ellipsis-vert": ctrl.pane == "board"
5741
+ },
5742
+ hook: {
5743
+ insert: (vnode2) => {
5744
+ const el = vnode2.elm;
5745
+ el.addEventListener("click", ctrl.toggleMenu);
5746
+ ctrl.menuButton = el;
5747
+ }
5748
+ },
5749
+ attrs: {
5750
+ "aria-label": ctrl.translate("menu"),
5751
+ "aria-expanded": String(ctrl.pane === "menu"),
5752
+ "aria-haspopup": "menu"
5753
+ }
5754
+ },
5755
+ ctrl.pane == "board" ? void 0 : "X"
5756
+ ),
5757
+ dirButton(ctrl, "next", "right-open"),
5758
+ ctrl.pane == "board" ? void 0 : dirButton(ctrl, "last", "step-forward")
5759
+ ]
5760
+ );
5761
+ var dirButton = (ctrl, to, icon) => {
5762
+ const isDisabled = ctrl.pane == "board" && !ctrl.canGoTo(to);
5763
+ return h(`button.lpv__controls__goto.lpv__controls__goto--${to}.lpv__fbt.lpv__icon.lpv__icon-${icon}`, {
5764
+ class: { disabled: isDisabled },
5765
+ hook: onInsert((el) => bindMobileMousedown(el, (e) => eventRepeater(() => ctrl.goTo(to), e))),
5766
+ attrs: {
5767
+ "aria-label": ctrl.translate(`aria.${to}`),
5768
+ "aria-disabled": String(isDisabled),
5769
+ disabled: isDisabled
5770
+ }
5771
+ });
5772
+ };
5773
+ var setupMenuKeyboard = (ctrl, menuEl) => {
5774
+ const handleMenuKeydown = (e) => {
5775
+ switch (e.key) {
5776
+ case "Enter":
5777
+ case " ":
5778
+ e.preventDefault();
5779
+ document.activeElement?.click();
5780
+ break;
5781
+ case "Escape":
5782
+ e.preventDefault();
5783
+ ctrl.toggleMenu();
5784
+ break;
5785
+ }
5786
+ };
5787
+ menuEl.addEventListener("keydown", handleMenuKeydown);
5788
+ };
5789
+
5790
+ // src/view/aria.ts
5791
+ var ariaHidden = { "aria-hidden": true };
5792
+ var presentation = { role: "presentation", "aria-hidden": "true" };
5793
+ var renderAriaAnnouncement = (ctrl) => {
5794
+ const data = ctrl.curData();
5795
+ if (!isMoveData(data)) return "";
5796
+ const moveNumber = Math.ceil(data.ply / 2);
5797
+ const color = data.ply % 2 === 1 ? "white" : "black";
5798
+ const san = data.san;
5799
+ let announcement = ctrl.translate(
5800
+ "aria.move",
5801
+ moveNumber.toString(),
5802
+ ctrl.translate(`aria.${color}`),
5803
+ formatMoveForScreenReader(san, data.nags, ctrl.translate)
5804
+ );
5805
+ const clock = data.clocks && data.clocks[color === "white" ? "white" : "black"];
5806
+ if (clock !== void 0 && ctrl.opts.showClocks) {
5807
+ const clockTime = clockContent(clock).join("");
5808
+ if (clockTime !== "-") {
5809
+ announcement += ", " + ctrl.translate("aria.remaining", clockTime);
5810
+ }
5811
+ }
5812
+ const comments = data.comments.join(" ").trim();
5813
+ if (comments) {
5814
+ announcement += `. ${comments}`;
5815
+ }
5816
+ return announcement;
5817
+ };
5818
+ var renderRootAriaLabel = (ctrl) => {
5819
+ const game = ctrl.game;
5820
+ const formatPlayer = (player) => {
5821
+ let playerInfo = player.name || ctrl.translate("aria.unknownPlayer");
5822
+ if (player.title) {
5823
+ playerInfo = `${player.title} ${playerInfo}`;
5824
+ }
5825
+ if (player.rating) {
5826
+ playerInfo = `${playerInfo}, ${ctrl.translate("aria.rated", player.rating.toString())}`;
5827
+ }
5828
+ return playerInfo;
5829
+ };
5830
+ const formatResult = (result2) => {
5831
+ if (!result2 || result2 === "*") return ctrl.translate("aria.gameInProgress");
5832
+ if (result2 === "1-0") return ctrl.translate("aria.whitesWin");
5833
+ if (result2 === "0-1") return ctrl.translate("aria.blacksWin");
5834
+ if (result2 === "1/2-1/2") return ctrl.translate("aria.draw");
5835
+ return result2;
5836
+ };
5837
+ const whiteName = formatPlayer(game.players.white);
5838
+ const blackName = formatPlayer(game.players.black);
5839
+ const result = formatResult(game.metadata.result);
5840
+ return ctrl.translate("aria.chessGameBetween", whiteName, blackName, result);
5841
+ };
5842
+
5614
5843
  // src/view/side.ts
5615
5844
  var renderMoves = (ctrl) => h("div.lpv__side", [
5616
5845
  h(
5617
5846
  "div.lpv__moves",
5618
5847
  {
5848
+ attrs: {
5849
+ role: "complementary",
5850
+ "aria-label": ctrl.translate("aria.gameMoves")
5851
+ },
5619
5852
  hook: {
5620
5853
  insert: (vnode2) => {
5621
5854
  const el = vnode2.elm;
5622
5855
  if (!ctrl.path.empty()) autoScroll(ctrl, el);
5623
5856
  el.addEventListener(
5624
- "mousedown",
5625
- (e2) => {
5626
- const path = e2.target.getAttribute("p");
5857
+ "click",
5858
+ (e) => {
5859
+ const path = e.target.getAttribute("data-path");
5627
5860
  if (path) ctrl.toPath(new Path(path));
5628
5861
  },
5629
5862
  { passive: true }
@@ -5642,13 +5875,19 @@ var renderMoves = (ctrl) => h("div.lpv__side", [
5642
5875
  ]);
5643
5876
  var renderResultComment = (ctrl) => {
5644
5877
  const res = ctrl.game.metadata.result;
5645
- return res && res != "*" ? [h("comment.result", ctrl.game.metadata.result)] : [];
5878
+ return res && res != "*" ? [
5879
+ h(
5880
+ "comment.result",
5881
+ { attrs: { role: "note", "aria-label": ctrl.translate("aria.gameResult") } },
5882
+ ctrl.game.metadata.result
5883
+ )
5884
+ ] : [];
5646
5885
  };
5647
- var emptyMove = () => h("move.empty", "...");
5648
- var indexNode = (turn) => h("index", `${turn}.`);
5649
- var commentNode = (comment) => h("comment", comment);
5650
- var parenOpen = () => h("paren.open", "(");
5651
- var parenClose = () => h("paren.close", ")");
5886
+ var emptyMove = () => h("button.move.empty", { attrs: { "aria-hidden": "true", disabled: true } }, "...");
5887
+ var indexNode = (turn) => h("index", { attrs: presentation }, `${turn}.`);
5888
+ var commentNode = (comment) => h("comment", { attrs: { role: "note" } }, comment);
5889
+ var parenOpen = () => h("paren.open", { attrs: ariaHidden }, "(");
5890
+ var parenClose = () => h("paren.close", { attrs: ariaHidden }, ")");
5652
5891
  var moveTurn = (move3) => Math.floor((move3.ply - 1) / 2) + 1;
5653
5892
  var makeMoveNodes = (ctrl) => {
5654
5893
  const moveDom = renderMove(ctrl);
@@ -5664,20 +5903,23 @@ var makeMoveNodes = (ctrl) => {
5664
5903
  const addEmptyMove = oddMove && (variations.length || move3.comments.length) && node.children.length;
5665
5904
  if (addEmptyMove) elms.push(emptyMove());
5666
5905
  move3.comments.forEach((comment) => elms.push(commentNode(comment)));
5667
- variations.forEach((variation) => elms.push(makeMainVariation(moveDom, variation)));
5906
+ variations.forEach((variation) => elms.push(makeMainVariation(ctrl.translate, moveDom, variation)));
5668
5907
  if (addEmptyMove) elms.push(indexNode(moveTurn(move3)), emptyMove());
5669
5908
  variations = node.children.slice(1);
5670
5909
  }
5671
5910
  return elms;
5672
5911
  };
5673
- var makeMainVariation = (moveDom, node) => h("variation", [...node.data.startingComments.map(commentNode), ...makeVariationMoves(moveDom, node)]);
5912
+ var makeMainVariation = (translate3, moveDom, node) => h("variation", { attrs: { role: "group", "aria-label": translate3("aria.variation") } }, [
5913
+ ...node.data.startingComments.map(commentNode),
5914
+ ...makeVariationMoves(moveDom, node)
5915
+ ]);
5674
5916
  var makeVariationMoves = (moveDom, node) => {
5675
5917
  let elms = [];
5676
5918
  let variations = [];
5677
- if (node.data.ply % 2 == 0) elms.push(h("index", [moveTurn(node.data), "..."]));
5919
+ if (node.data.ply % 2 == 0) elms.push(h("index", { attrs: presentation }, [moveTurn(node.data), "..."]));
5678
5920
  do {
5679
5921
  const move3 = node.data;
5680
- if (move3.ply % 2 == 1) elms.push(h("index", [moveTurn(move3), "."]));
5922
+ if (move3.ply % 2 == 1) elms.push(h("index", { attrs: presentation }, [moveTurn(move3), "."]));
5681
5923
  elms.push(moveDom(move3));
5682
5924
  move3.comments.forEach((comment) => elms.push(commentNode(comment)));
5683
5925
  variations.forEach((variation) => {
@@ -5689,7 +5931,7 @@ var makeVariationMoves = (moveDom, node) => {
5689
5931
  return elms;
5690
5932
  };
5691
5933
  var renderMove = (ctrl) => (move3) => h(
5692
- "move",
5934
+ "button.move",
5693
5935
  {
5694
5936
  class: {
5695
5937
  current: ctrl.path.equals(move3.path),
@@ -5702,7 +5944,14 @@ var renderMove = (ctrl) => (move3) => h(
5702
5944
  inaccuracy: move3.nags.includes(6)
5703
5945
  },
5704
5946
  attrs: {
5705
- p: move3.path.path
5947
+ "data-path": move3.path.path,
5948
+ role: "button",
5949
+ "aria-label": ctrl.translate(
5950
+ "aria.move",
5951
+ Math.ceil(move3.ply / 2).toString(),
5952
+ ctrl.translate(`aria.${move3.ply % 2 === 1 ? "white" : "black"}`),
5953
+ formatMoveForScreenReader(move3.san, move3.nags, ctrl.translate)
5954
+ )
5706
5955
  }
5707
5956
  },
5708
5957
  [move3.san, ...move3.nags.map(renderNag)]
@@ -5726,9 +5975,14 @@ function renderPlayer(ctrl, side) {
5726
5975
  player.rating ? h("span.lpv__player__rating", ["(", player.rating, ")"]) : void 0
5727
5976
  ];
5728
5977
  return h(`div.lpv__player.lpv__player--${side}`, [
5729
- player.isLichessUser ? h(
5978
+ player.isLichessUser && player.name ? h(
5730
5979
  "a.lpv__player__person.ulpt.user-link",
5731
- { attrs: { href: `${ctrl.opts.lichess}/@/${player.name}` } },
5980
+ {
5981
+ attrs: {
5982
+ href: `${ctrl.opts.lichess}/@/${player.name}`,
5983
+ "aria-label": ctrl.translate("aria.viewProfileOnLichess", player.name)
5984
+ }
5985
+ },
5732
5986
  personEls
5733
5987
  ) : h("span.lpv__player__person", personEls),
5734
5988
  ctrl.opts.showClocks ? renderClock(ctrl, color) : void 0
@@ -5737,14 +5991,67 @@ function renderPlayer(ctrl, side) {
5737
5991
  var renderClock = (ctrl, color) => {
5738
5992
  const move3 = ctrl.curData();
5739
5993
  const clock = move3.clocks && move3.clocks[color];
5740
- return typeof clock == void 0 ? void 0 : h("div.lpv__player__clock", { class: { active: color == move3.turn } }, clockContent(clock));
5994
+ return typeof clock == void 0 ? void 0 : h(
5995
+ "div.lpv__player__clock",
5996
+ {
5997
+ class: { active: color == move3.turn },
5998
+ attrs: {
5999
+ role: "timer",
6000
+ "aria-label": clockContent(clock).join("")
6001
+ }
6002
+ },
6003
+ clockContent(clock)
6004
+ );
5741
6005
  };
5742
- var clockContent = (seconds) => {
5743
- if (!seconds && seconds !== 0) return ["-"];
5744
- const date = new Date(seconds * 1e3), sep = ":", baseStr = pad2(date.getUTCMinutes()) + sep + pad2(date.getUTCSeconds());
5745
- return seconds >= 3600 ? [Math.floor(seconds / 3600) + sep + baseStr] : [baseStr];
6006
+
6007
+ // src/view/accessibleBoard.ts
6008
+ var renderAccessibleBoard = (ctrl) => {
6009
+ const flipped = ctrl.flipped;
6010
+ return h(
6011
+ "div.lpv__sr-only",
6012
+ {
6013
+ attrs: {
6014
+ role: "grid",
6015
+ "aria-label": ctrl.translate("aria.accessibleChessboard"),
6016
+ "aria-hidden": "false"
6017
+ }
6018
+ },
6019
+ renderBoardRows(ctrl, flipped)
6020
+ );
6021
+ };
6022
+ var renderBoardRows = (ctrl, flipped) => {
6023
+ const pieces = ctrl.ground?.state.pieces || read(ctrl.curData().fen);
6024
+ const orderedRanks = flipped ? ranks : invRanks;
6025
+ const orderedFiles = flipped ? [...files].reverse() : files;
6026
+ return orderedRanks.map(
6027
+ (rank) => h(
6028
+ "div",
6029
+ {
6030
+ attrs: {
6031
+ role: "row"
6032
+ }
6033
+ },
6034
+ orderedFiles.map((file) => {
6035
+ const squareKey = `${file}${rank}`;
6036
+ const piece = pieces.get(squareKey);
6037
+ return renderSquare(ctrl.translate, file, rank, piece);
6038
+ })
6039
+ )
6040
+ );
6041
+ };
6042
+ var renderSquare = (translate3, file, rank, piece) => {
6043
+ const ariaLabel = formatSquareForScreenReader(translate3, file, rank, piece);
6044
+ return h(
6045
+ "span",
6046
+ {
6047
+ attrs: {
6048
+ role: "gridcell",
6049
+ "aria-label": ariaLabel
6050
+ }
6051
+ },
6052
+ ariaLabel
6053
+ );
5746
6054
  };
5747
- var pad2 = (num) => (num < 10 ? "0" : "") + num;
5748
6055
 
5749
6056
  // src/view/main.ts
5750
6057
  function view(ctrl) {
@@ -5758,7 +6065,9 @@ function view(ctrl) {
5758
6065
  "lpv--players": showPlayers
5759
6066
  },
5760
6067
  attrs: {
5761
- tabindex: 0
6068
+ role: "region",
6069
+ tabindex: 0,
6070
+ "aria-label": renderRootAriaLabel(ctrl)
5762
6071
  },
5763
6072
  hook: onInsert((el) => {
5764
6073
  ctrl.setGround(Chessground(el.querySelector(".cg-wrap"), makeConfig(ctrl, el)));
@@ -5766,6 +6075,14 @@ function view(ctrl) {
5766
6075
  })
5767
6076
  },
5768
6077
  [
6078
+ h(
6079
+ "div.lpv__sr-only",
6080
+ {
6081
+ attrs: { "aria-live": "polite", "aria-atomic": "true" }
6082
+ },
6083
+ renderAriaAnnouncement(ctrl)
6084
+ ),
6085
+ renderAccessibleBoard(ctrl),
5769
6086
  showPlayers ? renderPlayer(ctrl, "top") : void 0,
5770
6087
  renderBoard(ctrl),
5771
6088
  showPlayers ? renderPlayer(ctrl, "bottom") : void 0,
@@ -5778,15 +6095,16 @@ function view(ctrl) {
5778
6095
  var renderBoard = (ctrl) => h(
5779
6096
  "div.lpv__board",
5780
6097
  {
6098
+ attrs: ariaHidden,
5781
6099
  hook: onInsert((el) => {
5782
6100
  el.addEventListener("click", ctrl.focus);
5783
6101
  if (ctrl.opts.scrollToMove && !("ontouchstart" in window))
5784
6102
  el.addEventListener(
5785
6103
  "wheel",
5786
- stepwiseScroll((e2, scroll) => {
5787
- e2.preventDefault();
5788
- if (e2.deltaY > 0 && scroll) ctrl.goTo("next", false);
5789
- else if (e2.deltaY < 0 && scroll) ctrl.goTo("prev", false);
6104
+ stepwiseScroll((e, scroll) => {
6105
+ e.preventDefault();
6106
+ if (e.deltaY > 0 && scroll) ctrl.goTo("next", false);
6107
+ else if (e.deltaY < 0 && scroll) ctrl.goTo("prev", false);
5790
6108
  })
5791
6109
  );
5792
6110
  })