@lichess-org/pgn-viewer 2.5.1 → 2.5.3

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.
@@ -917,8 +917,8 @@ var Position = class {
917
917
  return this.board[color].size() <= 2 && this.board[opposite(color)].diff(this.board.king).diff(this.board.queen).isEmpty();
918
918
  }
919
919
  if (this.board[color].intersects(this.board.bishop)) {
920
- const sameColor = !this.board.bishop.intersects(SquareSet.darkSquares()) || !this.board.bishop.intersects(SquareSet.lightSquares());
921
- return sameColor && this.board.pawn.isEmpty() && this.board.knight.isEmpty();
920
+ const sameColor2 = !this.board.bishop.intersects(SquareSet.darkSquares()) || !this.board.bishop.intersects(SquareSet.lightSquares());
921
+ return sameColor2 && this.board.pawn.isEmpty() && this.board.knight.isEmpty();
922
922
  }
923
923
  return true;
924
924
  }
@@ -2698,15 +2698,16 @@ var defaultTranslations = {
2698
2698
  "san.shortCastling": "short castling"
2699
2699
  };
2700
2700
 
2701
- // node_modules/.pnpm/chessground@9.2.1/node_modules/chessground/dist/types.js
2701
+ // node_modules/.pnpm/@lichess-org+chessground@9.8.5/node_modules/@lichess-org/chessground/dist/types.js
2702
2702
  var colors = ["white", "black"];
2703
2703
  var files = ["a", "b", "c", "d", "e", "f", "g", "h"];
2704
2704
  var ranks = ["1", "2", "3", "4", "5", "6", "7", "8"];
2705
2705
 
2706
- // node_modules/.pnpm/chessground@9.2.1/node_modules/chessground/dist/util.js
2706
+ // node_modules/.pnpm/@lichess-org+chessground@9.8.5/node_modules/@lichess-org/chessground/dist/util.js
2707
2707
  var invRanks = [...ranks].reverse();
2708
- var allKeys = Array.prototype.concat(...files.map((c) => ranks.map((r) => c + r)));
2709
- var pos2key = (pos) => allKeys[8 * pos[0] + pos[1]];
2708
+ var allKeys = files.flatMap((f) => ranks.map((r) => f + r));
2709
+ var pos2key = (pos) => pos.every((x) => x >= 0 && x <= 7) ? allKeys[8 * pos[0] + pos[1]] : void 0;
2710
+ var pos2keyUnsafe = (pos) => pos2key(pos);
2710
2711
  var key2pos = (k) => [k.charCodeAt(0) - 97, k.charCodeAt(1) - 49];
2711
2712
  var uciToMove = (uci) => {
2712
2713
  if (!uci)
@@ -2716,6 +2717,7 @@ var uciToMove = (uci) => {
2716
2717
  return [uci.slice(0, 2), uci.slice(2, 4)];
2717
2718
  };
2718
2719
  var allPos = allKeys.map(key2pos);
2720
+ var allPosAndKey = allKeys.map((key, i) => ({ key, pos: allPos[i] }));
2719
2721
  function memo(f) {
2720
2722
  let v;
2721
2723
  const ret = () => {
@@ -2747,11 +2749,9 @@ var timer = () => {
2747
2749
  };
2748
2750
  };
2749
2751
  var opposite2 = (c) => c === "white" ? "black" : "white";
2750
- var distanceSq = (pos1, pos2) => {
2751
- const dx = pos1[0] - pos2[0], dy = pos1[1] - pos2[1];
2752
- return dx * dx + dy * dy;
2753
- };
2752
+ var distanceSq = (pos1, pos2) => (pos1[0] - pos2[0]) ** 2 + (pos1[1] - pos2[1]) ** 2;
2754
2753
  var samePiece = (p1, p2) => p1.role === p2.role && p1.color === p2.color;
2754
+ var samePos = (p1, p2) => p1[0] === p2[0] && p1[1] === p2[1];
2755
2755
  var posToTranslate = (bounds) => (pos, asWhite) => [
2756
2756
  (asWhite ? pos[0] : 7 - pos[0]) * bounds.width / 8,
2757
2757
  (asWhite ? 7 - pos[1] : pos[1]) * bounds.height / 8
@@ -2766,14 +2766,14 @@ var setVisible = (el, v) => {
2766
2766
  el.style.visibility = v ? "visible" : "hidden";
2767
2767
  };
2768
2768
  var eventPosition = (e) => {
2769
- var _a;
2770
2769
  if (e.clientX || e.clientX === 0)
2771
2770
  return [e.clientX, e.clientY];
2772
- if ((_a = e.targetTouches) === null || _a === void 0 ? void 0 : _a[0])
2771
+ if (e.targetTouches?.[0])
2773
2772
  return [e.targetTouches[0].clientX, e.targetTouches[0].clientY];
2774
2773
  return;
2775
2774
  };
2776
- var isRightButton = (e) => e.button === 2;
2775
+ var isFireMac = memo(() => !("ontouchstart" in window) && ["macintosh", "firefox"].every((x) => navigator.userAgent.toLowerCase().includes(x)));
2776
+ var isRightButton = (e) => e.button === 2 && !(e.ctrlKey && isFireMac());
2777
2777
  var createEl = (tagName2, className) => {
2778
2778
  const el = document.createElement(tagName2);
2779
2779
  if (className)
@@ -2791,6 +2791,47 @@ function computeSquareCenter(key, asWhite, bounds) {
2791
2791
  bounds.top + bounds.height * (7 - pos[1]) / 8 + bounds.height / 16
2792
2792
  ];
2793
2793
  }
2794
+ var diff = (a, b) => Math.abs(a - b);
2795
+ var knightDir = (x1, y1, x2, y2) => diff(x1, x2) * diff(y1, y2) === 2;
2796
+ var rookDir = (x1, y1, x2, y2) => x1 === x2 !== (y1 === y2);
2797
+ var bishopDir = (x1, y1, x2, y2) => diff(x1, x2) === diff(y1, y2) && x1 !== x2;
2798
+ var queenDir = (x1, y1, x2, y2) => rookDir(x1, y1, x2, y2) || bishopDir(x1, y1, x2, y2);
2799
+ var kingDirNonCastling = (x1, y1, x2, y2) => Math.max(diff(x1, x2), diff(y1, y2)) === 1;
2800
+ var pawnDirCapture = (x1, y1, x2, y2, isDirectionUp) => diff(x1, x2) === 1 && y2 === y1 + (isDirectionUp ? 1 : -1);
2801
+ var pawnDirAdvance = (x1, y1, x2, y2, isDirectionUp) => {
2802
+ const step2 = isDirectionUp ? 1 : -1;
2803
+ return x1 === x2 && (y2 === y1 + step2 || // allow 2 squares from first two ranks, for horde
2804
+ y2 === y1 + 2 * step2 && (isDirectionUp ? y1 <= 1 : y1 >= 6));
2805
+ };
2806
+ var squaresBetween = (x1, y1, x2, y2) => {
2807
+ const dx = x2 - x1;
2808
+ const dy = y2 - y1;
2809
+ if (dx && dy && Math.abs(dx) !== Math.abs(dy))
2810
+ return [];
2811
+ const stepX = Math.sign(dx), stepY = Math.sign(dy);
2812
+ const squares = [];
2813
+ let x = x1 + stepX, y = y1 + stepY;
2814
+ while (x !== x2 || y !== y2) {
2815
+ squares.push([x, y]);
2816
+ x += stepX;
2817
+ y += stepY;
2818
+ }
2819
+ return squares.map(pos2key).filter((k) => k !== void 0);
2820
+ };
2821
+ var adjacentSquares = (square) => {
2822
+ const pos = key2pos(square);
2823
+ const adjacentSquares2 = [];
2824
+ if (pos[0] > 0)
2825
+ adjacentSquares2.push([pos[0] - 1, pos[1]]);
2826
+ if (pos[0] < 7)
2827
+ adjacentSquares2.push([pos[0] + 1, pos[1]]);
2828
+ return adjacentSquares2.map(pos2key).filter((k) => k !== void 0);
2829
+ };
2830
+ var squareShiftedVertically = (square, delta) => {
2831
+ const pos = key2pos(square);
2832
+ pos[1] += delta;
2833
+ return pos2key(pos);
2834
+ };
2794
2835
 
2795
2836
  // src/path.ts
2796
2837
  var Path = class _Path {
@@ -3042,46 +3083,125 @@ var PgnViewer = class {
3042
3083
  }
3043
3084
  };
3044
3085
 
3045
- // node_modules/.pnpm/chessground@9.2.1/node_modules/chessground/dist/premove.js
3046
- var diff = (a, b) => Math.abs(a - b);
3047
- var pawn = (color) => (x1, y1, x2, y2) => diff(x1, x2) < 2 && (color === "white" ? (
3048
- // allow 2 squares from first two ranks, for horde
3049
- y2 === y1 + 1 || y1 <= 1 && y2 === y1 + 2 && x1 === x2
3050
- ) : y2 === y1 - 1 || y1 >= 6 && y2 === y1 - 2 && x1 === x2);
3051
- var knight = (x1, y1, x2, y2) => {
3052
- const xd = diff(x1, x2);
3053
- const yd = diff(y1, y2);
3054
- return xd === 1 && yd === 2 || xd === 2 && yd === 1;
3086
+ // node_modules/.pnpm/@lichess-org+chessground@9.8.5/node_modules/@lichess-org/chessground/dist/premove.js
3087
+ var isDestOccupiedByFriendly = (ctx) => ctx.friendlies.has(ctx.dest.key);
3088
+ var isDestOccupiedByEnemy = (ctx) => ctx.enemies.has(ctx.dest.key);
3089
+ var anyPieceBetween = (orig, dest, pieces) => squaresBetween(...orig, ...dest).some((s) => pieces.has(s));
3090
+ var canEnemyPawnAdvanceToSquare = (pawnStart, dest, ctx) => {
3091
+ const piece = ctx.enemies.get(pawnStart);
3092
+ if (piece?.role !== "pawn")
3093
+ return false;
3094
+ const step2 = piece.color === "white" ? 1 : -1;
3095
+ const startPos = key2pos(pawnStart);
3096
+ const destPos = key2pos(dest);
3097
+ return pawnDirAdvance(...startPos, ...destPos, piece.color === "white") && !anyPieceBetween(startPos, [destPos[0], destPos[1] + step2], ctx.allPieces);
3055
3098
  };
3056
- var bishop = (x1, y1, x2, y2) => {
3057
- return diff(x1, x2) === diff(y1, y2);
3099
+ var canEnemyPawnCaptureOnSquare = (pawnStart, dest, ctx) => {
3100
+ const enemyPawn = ctx.enemies.get(pawnStart);
3101
+ return enemyPawn?.role === "pawn" && pawnDirCapture(...key2pos(pawnStart), ...key2pos(dest), enemyPawn.color === "white") && (ctx.friendlies.has(dest) || canBeCapturedBySomeEnemyEnPassant(squareShiftedVertically(dest, enemyPawn.color === "white" ? -1 : 1), ctx.friendlies, ctx.enemies, ctx.lastMove));
3058
3102
  };
3059
- var rook = (x1, y1, x2, y2) => {
3060
- return x1 === x2 || y1 === y2;
3103
+ var canSomeEnemyPawnAdvanceToDest = (ctx) => [...ctx.enemies.keys()].some((key) => canEnemyPawnAdvanceToSquare(key, ctx.dest.key, ctx));
3104
+ var isDestControlledByEnemy = (ctx, pieceRolesExclude) => {
3105
+ const square = ctx.dest.pos;
3106
+ return [...ctx.enemies].some(([key, piece]) => {
3107
+ const piecePos = key2pos(key);
3108
+ return !pieceRolesExclude?.includes(piece.role) && (piece.role === "pawn" && pawnDirCapture(...piecePos, ...square, piece.color === "white") || piece.role === "knight" && knightDir(...piecePos, ...square) || piece.role === "bishop" && bishopDir(...piecePos, ...square) || piece.role === "rook" && rookDir(...piecePos, ...square) || piece.role === "queen" && queenDir(...piecePos, ...square) || piece.role === "king" && kingDirNonCastling(...piecePos, ...square)) && (!["bishop", "rook", "queen"].includes(piece.role) || !anyPieceBetween(piecePos, square, ctx.allPieces));
3109
+ });
3061
3110
  };
3062
- var queen = (x1, y1, x2, y2) => {
3063
- return bishop(x1, y1, x2, y2) || rook(x1, y1, x2, y2);
3111
+ var isFriendlyOnDestAndAttacked = (ctx) => isDestOccupiedByFriendly(ctx) && (canBeCapturedBySomeEnemyEnPassant(ctx.dest.key, ctx.friendlies, ctx.enemies, ctx.lastMove) || isDestControlledByEnemy(ctx));
3112
+ var canBeCapturedBySomeEnemyEnPassant = (potentialSquareOfFriendlyPawn, friendlies, enemies, lastMove) => {
3113
+ if (!potentialSquareOfFriendlyPawn || lastMove && potentialSquareOfFriendlyPawn !== lastMove[1])
3114
+ return false;
3115
+ const pos = key2pos(potentialSquareOfFriendlyPawn);
3116
+ const friendly = friendlies.get(potentialSquareOfFriendlyPawn);
3117
+ return friendly?.role === "pawn" && pos[1] === (friendly.color === "white" ? 3 : 4) && (!lastMove || diff(key2pos(lastMove[0])[1], pos[1]) === 2) && [1, -1].some((delta) => {
3118
+ const k = pos2key([pos[0] + delta, pos[1]]);
3119
+ return !!k && enemies.get(k)?.role === "pawn";
3120
+ });
3064
3121
  };
3065
- var king = (color, rookFiles, canCastle) => (x1, y1, x2, y2) => diff(x1, x2) < 2 && diff(y1, y2) < 2 || canCastle && y1 === y2 && y1 === (color === "white" ? 0 : 7) && (x1 === 4 && (x2 === 2 && rookFiles.includes(0) || x2 === 6 && rookFiles.includes(7)) || rookFiles.includes(x2));
3066
- function rookFilesOf(pieces, color) {
3067
- const backrank = color === "white" ? "1" : "8";
3068
- const files2 = [];
3069
- for (const [key, piece] of pieces) {
3070
- if (key[1] === backrank && piece.color === color && piece.role === "rook") {
3071
- files2.push(key2pos(key)[0]);
3072
- }
3073
- }
3074
- return files2;
3075
- }
3076
- function premove(pieces, key, canCastle) {
3122
+ var isPathClearEnoughOfFriendliesForPremove = (ctx, isPawnAdvance) => {
3123
+ if (ctx.unrestrictedPremoves)
3124
+ return true;
3125
+ const squaresBetween2 = squaresBetween(...ctx.orig.pos, ...ctx.dest.pos);
3126
+ if (isPawnAdvance)
3127
+ squaresBetween2.push(ctx.dest.key);
3128
+ const squaresOfFriendliesBetween = squaresBetween2.filter((s) => ctx.friendlies.has(s));
3129
+ if (!squaresOfFriendliesBetween.length)
3130
+ return true;
3131
+ const firstSquareOfFriendliesBetween = squaresOfFriendliesBetween[0];
3132
+ const nextSquare = squareShiftedVertically(firstSquareOfFriendliesBetween, ctx.color === "white" ? -1 : 1);
3133
+ return squaresOfFriendliesBetween.length === 1 && canBeCapturedBySomeEnemyEnPassant(firstSquareOfFriendliesBetween, ctx.friendlies, ctx.enemies, ctx.lastMove) && !!nextSquare && !squaresBetween2.includes(nextSquare);
3134
+ };
3135
+ var isPathClearEnoughOfEnemiesForPremove = (ctx, isPawnAdvance) => {
3136
+ if (ctx.unrestrictedPremoves)
3137
+ return true;
3138
+ const squaresBetween2 = squaresBetween(...ctx.orig.pos, ...ctx.dest.pos);
3139
+ if (isPawnAdvance)
3140
+ squaresBetween2.push(ctx.dest.key);
3141
+ const squaresOfEnemiesBetween = squaresBetween2.filter((s) => ctx.enemies.has(s));
3142
+ if (squaresOfEnemiesBetween.length > 1)
3143
+ return false;
3144
+ if (!squaresOfEnemiesBetween.length)
3145
+ return true;
3146
+ const enemySquare = squaresOfEnemiesBetween[0];
3147
+ const enemy = ctx.enemies.get(enemySquare);
3148
+ if (!enemy || enemy.role !== "pawn")
3149
+ return true;
3150
+ const enemyStep = enemy.color === "white" ? 1 : -1;
3151
+ const squareAbove = squareShiftedVertically(enemySquare, enemyStep);
3152
+ const enemyPawnDests = squareAbove ? [
3153
+ ...adjacentSquares(squareAbove).filter((s) => canEnemyPawnCaptureOnSquare(enemySquare, s, ctx)),
3154
+ ...[squareAbove, squareShiftedVertically(squareAbove, enemyStep)].filter((s) => !!s).filter((s) => canEnemyPawnAdvanceToSquare(enemySquare, s, ctx))
3155
+ ] : [];
3156
+ const badSquares = [...squaresBetween2, ctx.orig.key];
3157
+ return enemyPawnDests.some((square) => !badSquares.includes(square));
3158
+ };
3159
+ var isPathClearEnoughForPremove = (ctx, isPawnAdvance) => isPathClearEnoughOfFriendliesForPremove(ctx, isPawnAdvance) && isPathClearEnoughOfEnemiesForPremove(ctx, isPawnAdvance);
3160
+ var pawn = (ctx) => {
3161
+ const step2 = ctx.color === "white" ? 1 : -1;
3162
+ if (diff(ctx.orig.pos[0], ctx.dest.pos[0]) > 1)
3163
+ return false;
3164
+ if (!diff(ctx.orig.pos[0], ctx.dest.pos[0]))
3165
+ return pawnDirAdvance(...ctx.orig.pos, ...ctx.dest.pos, ctx.color === "white") && isPathClearEnoughForPremove(ctx, true);
3166
+ if (ctx.dest.pos[1] !== ctx.orig.pos[1] + step2)
3167
+ return false;
3168
+ if (ctx.unrestrictedPremoves || isDestOccupiedByEnemy(ctx))
3169
+ return true;
3170
+ if (isDestOccupiedByFriendly(ctx))
3171
+ return isDestControlledByEnemy(ctx);
3172
+ else
3173
+ return canSomeEnemyPawnAdvanceToDest(ctx) || canBeCapturedBySomeEnemyEnPassant(pos2key([ctx.dest.pos[0], ctx.dest.pos[1] + step2]), ctx.friendlies, ctx.enemies, ctx.lastMove) || isDestControlledByEnemy(ctx, ["pawn"]);
3174
+ };
3175
+ var knight = (ctx) => knightDir(...ctx.orig.pos, ...ctx.dest.pos) && (ctx.unrestrictedPremoves || !isDestOccupiedByFriendly(ctx) || isFriendlyOnDestAndAttacked(ctx));
3176
+ var bishop = (ctx) => bishopDir(...ctx.orig.pos, ...ctx.dest.pos) && isPathClearEnoughForPremove(ctx, false) && (ctx.unrestrictedPremoves || !isDestOccupiedByFriendly(ctx) || isFriendlyOnDestAndAttacked(ctx));
3177
+ var rook = (ctx) => rookDir(...ctx.orig.pos, ...ctx.dest.pos) && isPathClearEnoughForPremove(ctx, false) && (ctx.unrestrictedPremoves || !isDestOccupiedByFriendly(ctx) || isFriendlyOnDestAndAttacked(ctx));
3178
+ var queen = (ctx) => bishop(ctx) || rook(ctx);
3179
+ var king = (ctx) => kingDirNonCastling(...ctx.orig.pos, ...ctx.dest.pos) && (ctx.unrestrictedPremoves || !isDestOccupiedByFriendly(ctx) || isFriendlyOnDestAndAttacked(ctx)) || ctx.canCastle && ctx.orig.pos[1] === ctx.dest.pos[1] && ctx.orig.pos[1] === (ctx.color === "white" ? 0 : 7) && (ctx.orig.pos[0] === 4 && (ctx.dest.pos[0] === 2 && ctx.rookFilesFriendlies.includes(0) || ctx.dest.pos[0] === 6 && ctx.rookFilesFriendlies.includes(7)) || ctx.rookFilesFriendlies.includes(ctx.dest.pos[0])) && (ctx.unrestrictedPremoves || /* The following checks if no non-rook friendly piece is in the way between the king and its castling destination.
3180
+ Note that for the Chess960 edge case of Kb1 "long castling", the check passes even if there is a piece in the way
3181
+ on c1. But this is fine, since premoving from b1 to a1 as a normal move would have already returned true. */
3182
+ squaresBetween(...ctx.orig.pos, ctx.dest.pos[0] > ctx.orig.pos[0] ? 7 : 1, ctx.dest.pos[1]).map((s) => ctx.allPieces.get(s)).every((p) => !p || samePiece(p, { role: "rook", color: ctx.color })));
3183
+ var mobilityByRole = { pawn, knight, bishop, rook, queen, king };
3184
+ function premove(state, key) {
3185
+ const pieces = state.pieces, canCastle = state.premovable.castle, unrestrictedPremoves = !!state.premovable.unrestrictedPremoves;
3077
3186
  const piece = pieces.get(key);
3078
- if (!piece)
3187
+ if (!piece || piece.color === state.turnColor)
3079
3188
  return [];
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);
3081
- return allPos.filter((pos2) => (pos[0] !== pos2[0] || pos[1] !== pos2[1]) && mobility(pos[0], pos[1], pos2[0], pos2[1])).map(pos2key);
3189
+ const color = piece.color, friendlies = new Map([...pieces].filter(([_, p]) => p.color === color)), enemies = new Map([...pieces].filter(([_, p]) => p.color === opposite2(color))), orig = { key, pos: key2pos(key) }, mobility = (ctx) => mobilityByRole[piece.role](ctx) && state.premovable.additionalPremoveRequirements(ctx), partialCtx = {
3190
+ orig,
3191
+ role: piece.role,
3192
+ allPieces: pieces,
3193
+ friendlies,
3194
+ enemies,
3195
+ unrestrictedPremoves,
3196
+ color,
3197
+ canCastle,
3198
+ rookFilesFriendlies: Array.from(pieces).filter(([k, p]) => k[1] === (color === "white" ? "1" : "8") && p.color === color && p.role === "rook").map(([k]) => key2pos(k)[0]),
3199
+ lastMove: state.lastMove
3200
+ };
3201
+ return allPosAndKey.filter((dest) => mobility({ ...partialCtx, dest })).map((pk) => pk.key);
3082
3202
  }
3083
3203
 
3084
- // node_modules/.pnpm/chessground@9.2.1/node_modules/chessground/dist/board.js
3204
+ // node_modules/.pnpm/@lichess-org+chessground@9.8.5/node_modules/@lichess-org/chessground/dist/board.js
3085
3205
  function callUserFunction(f, ...args) {
3086
3206
  if (f)
3087
3207
  setTimeout(() => f(...args), 1);
@@ -3144,9 +3264,9 @@ function tryAutoCastle(state, orig, dest) {
3144
3264
  return false;
3145
3265
  if (origPos[0] === 4 && !state.pieces.has(dest)) {
3146
3266
  if (destPos[0] === 6)
3147
- dest = pos2key([7, destPos[1]]);
3267
+ dest = pos2keyUnsafe([7, destPos[1]]);
3148
3268
  else if (destPos[0] === 2)
3149
- dest = pos2key([0, destPos[1]]);
3269
+ dest = pos2keyUnsafe([0, destPos[1]]);
3150
3270
  }
3151
3271
  const rook2 = state.pieces.get(dest);
3152
3272
  if (!rook2 || rook2.color !== king2.color || rook2.role !== "rook")
@@ -3154,11 +3274,11 @@ function tryAutoCastle(state, orig, dest) {
3154
3274
  state.pieces.delete(orig);
3155
3275
  state.pieces.delete(dest);
3156
3276
  if (origPos[0] < destPos[0]) {
3157
- state.pieces.set(pos2key([6, destPos[1]]), king2);
3158
- state.pieces.set(pos2key([5, destPos[1]]), rook2);
3277
+ state.pieces.set(pos2keyUnsafe([6, destPos[1]]), king2);
3278
+ state.pieces.set(pos2keyUnsafe([5, destPos[1]]), rook2);
3159
3279
  } else {
3160
- state.pieces.set(pos2key([2, destPos[1]]), king2);
3161
- state.pieces.set(pos2key([3, destPos[1]]), rook2);
3280
+ state.pieces.set(pos2keyUnsafe([2, destPos[1]]), king2);
3281
+ state.pieces.set(pos2keyUnsafe([3, destPos[1]]), rook2);
3162
3282
  }
3163
3283
  return true;
3164
3284
  }
@@ -3269,12 +3389,10 @@ function selectSquare(state, key, force) {
3269
3389
  }
3270
3390
  function setSelected(state, key) {
3271
3391
  state.selected = key;
3272
- if (isPremovable(state, key)) {
3273
- if (!state.premovable.customDests) {
3274
- state.premovable.dests = premove(state.pieces, key, state.premovable.castle);
3275
- }
3276
- } else
3392
+ if (!isPremovable(state, key))
3277
3393
  state.premovable.dests = void 0;
3394
+ else if (!state.premovable.customDests)
3395
+ state.premovable.dests = premove(state, key);
3278
3396
  }
3279
3397
  function unselect(state) {
3280
3398
  state.selected = void 0;
@@ -3285,10 +3403,7 @@ function isMovable(state, orig) {
3285
3403
  const piece = state.pieces.get(orig);
3286
3404
  return !!piece && (state.movable.color === "both" || state.movable.color === piece.color && state.turnColor === piece.color);
3287
3405
  }
3288
- var canMove = (state, orig, dest) => {
3289
- var _a, _b;
3290
- return orig !== dest && isMovable(state, orig) && (state.movable.free || !!((_b = (_a = state.movable.dests) === null || _a === void 0 ? void 0 : _a.get(orig)) === null || _b === void 0 ? void 0 : _b.includes(dest)));
3291
- };
3406
+ var canMove = (state, orig, dest) => orig !== dest && isMovable(state, orig) && (state.movable.free || !!state.movable.dests?.get(orig)?.includes(dest));
3292
3407
  function canDrop(state, orig, dest) {
3293
3408
  const piece = state.pieces.get(orig);
3294
3409
  return !!piece && (orig === dest || !state.pieces.has(dest)) && (state.movable.color === "both" || state.movable.color === piece.color && state.turnColor === piece.color);
@@ -3297,11 +3412,7 @@ function isPremovable(state, orig) {
3297
3412
  const piece = state.pieces.get(orig);
3298
3413
  return !!piece && state.premovable.enabled && state.movable.color === piece.color && state.turnColor !== piece.color;
3299
3414
  }
3300
- function canPremove(state, orig, dest) {
3301
- var _a, _b;
3302
- const validPremoves = (_b = (_a = state.premovable.customDests) === null || _a === void 0 ? void 0 : _a.get(orig)) !== null && _b !== void 0 ? _b : premove(state.pieces, orig, state.premovable.castle);
3303
- return orig !== dest && isPremovable(state, orig) && validPremoves.includes(dest);
3304
- }
3415
+ var canPremove = (state, orig, dest) => orig !== dest && isPremovable(state, orig) && (state.premovable.customDests?.get(orig) ?? premove(state, orig)).includes(dest);
3305
3416
  function canPredrop(state, orig, dest) {
3306
3417
  const piece = state.pieces.get(orig);
3307
3418
  const destPiece = state.pieces.get(dest);
@@ -3371,15 +3482,15 @@ function getKeyAtDomPos(pos, asWhite, bounds) {
3371
3482
  }
3372
3483
  function getSnappedKeyAtDomPos(orig, pos, asWhite, bounds) {
3373
3484
  const origPos = key2pos(orig);
3374
- const validSnapPos = allPos.filter((pos2) => queen(origPos[0], origPos[1], pos2[0], pos2[1]) || knight(origPos[0], origPos[1], pos2[0], pos2[1]));
3375
- const validSnapCenters = validSnapPos.map((pos2) => computeSquareCenter(pos2key(pos2), asWhite, bounds));
3485
+ const validSnapPos = allPos.filter((pos2) => samePos(origPos, pos2) || queenDir(origPos[0], origPos[1], pos2[0], pos2[1]) || knightDir(origPos[0], origPos[1], pos2[0], pos2[1]));
3486
+ const validSnapCenters = validSnapPos.map((pos2) => computeSquareCenter(pos2keyUnsafe(pos2), asWhite, bounds));
3376
3487
  const validSnapDistances = validSnapCenters.map((pos2) => distanceSq(pos, pos2));
3377
3488
  const [, closestSnapIndex] = validSnapDistances.reduce((a, b, index) => a[0] < b ? a : [b, index], [validSnapDistances[0], 0]);
3378
3489
  return pos2key(validSnapPos[closestSnapIndex]);
3379
3490
  }
3380
3491
  var whitePov = (s) => s.orientation === "white";
3381
3492
 
3382
- // node_modules/.pnpm/chessground@9.2.1/node_modules/chessground/dist/fen.js
3493
+ // node_modules/.pnpm/@lichess-org+chessground@9.8.5/node_modules/@lichess-org/chessground/dist/fen.js
3383
3494
  var initial = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR";
3384
3495
  var roles = {
3385
3496
  p: "pawn",
@@ -3414,7 +3525,8 @@ function read(fen) {
3414
3525
  col = 0;
3415
3526
  break;
3416
3527
  case "~": {
3417
- const piece = pieces.get(pos2key([col - 1, row]));
3528
+ const k = pos2key([col - 1, row]);
3529
+ const piece = k && pieces.get(k);
3418
3530
  if (piece)
3419
3531
  piece.promoted = true;
3420
3532
  break;
@@ -3425,10 +3537,12 @@ function read(fen) {
3425
3537
  col += nb - 48;
3426
3538
  else {
3427
3539
  const role = c.toLowerCase();
3428
- pieces.set(pos2key([col, row]), {
3429
- role: roles[role],
3430
- color: c === role ? "black" : "white"
3431
- });
3540
+ const key = pos2key([col, row]);
3541
+ if (key)
3542
+ pieces.set(key, {
3543
+ role: roles[role],
3544
+ color: c === role ? "black" : "white"
3545
+ });
3432
3546
  ++col;
3433
3547
  }
3434
3548
  }
@@ -3451,7 +3565,7 @@ function write(pieces) {
3451
3565
  }).join("")).join("/").replace(/1{2,}/g, (s) => s.length.toString());
3452
3566
  }
3453
3567
 
3454
- // node_modules/.pnpm/chessground@9.2.1/node_modules/chessground/dist/config.js
3568
+ // node_modules/.pnpm/@lichess-org+chessground@9.8.5/node_modules/@lichess-org/chessground/dist/config.js
3455
3569
  function applyAnimation(state, config) {
3456
3570
  if (config.animation) {
3457
3571
  deepMerge(state.animation, config.animation);
@@ -3460,15 +3574,14 @@ function applyAnimation(state, config) {
3460
3574
  }
3461
3575
  }
3462
3576
  function configure(state, config) {
3463
- var _a, _b, _c;
3464
- if ((_a = config.movable) === null || _a === void 0 ? void 0 : _a.dests)
3577
+ if (config.movable?.dests)
3465
3578
  state.movable.dests = void 0;
3466
- if ((_b = config.drawable) === null || _b === void 0 ? void 0 : _b.autoShapes)
3579
+ if (config.drawable?.autoShapes)
3467
3580
  state.drawable.autoShapes = [];
3468
3581
  deepMerge(state, config);
3469
3582
  if (config.fen) {
3470
3583
  state.pieces = read(config.fen);
3471
- state.drawable.shapes = ((_c = config.drawable) === null || _c === void 0 ? void 0 : _c.shapes) || [];
3584
+ state.drawable.shapes = config.drawable?.shapes || [];
3472
3585
  }
3473
3586
  if ("check" in config)
3474
3587
  setCheck(state, config.check || false);
@@ -3503,7 +3616,7 @@ function isPlainObject(o) {
3503
3616
  return proto === Object.prototype || proto === null;
3504
3617
  }
3505
3618
 
3506
- // node_modules/.pnpm/chessground@9.2.1/node_modules/chessground/dist/anim.js
3619
+ // node_modules/.pnpm/@lichess-org+chessground@9.8.5/node_modules/@lichess-org/chessground/dist/anim.js
3507
3620
  var anim = (mutation, state) => state.animation.enabled ? animate(mutation, state) : render(mutation, state);
3508
3621
  function render(mutation, state) {
3509
3622
  const result = mutation(state);
@@ -3594,7 +3707,7 @@ function animate(mutation, state) {
3594
3707
  }
3595
3708
  var easing = (t) => t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1;
3596
3709
 
3597
- // node_modules/.pnpm/chessground@9.2.1/node_modules/chessground/dist/draw.js
3710
+ // node_modules/.pnpm/@lichess-org+chessground@9.8.5/node_modules/@lichess-org/chessground/dist/draw.js
3598
3711
  var brushes = ["green", "red", "blue", "yellow"];
3599
3712
  function start(state, e) {
3600
3713
  if (e.touches && e.touches.length > 1)
@@ -3656,18 +3769,18 @@ function clear(state) {
3656
3769
  onChange(state.drawable);
3657
3770
  }
3658
3771
  }
3772
+ var sameEndpoints = (s1, s2) => s1.orig === s2.orig && s1.dest === s2.dest;
3773
+ var sameColor = (s1, s2) => s1.brush === s2.brush;
3659
3774
  function eventBrush(e) {
3660
- var _a;
3661
3775
  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"));
3776
+ const modB = e.altKey || e.metaKey || e.getModifierState?.("AltGraph");
3663
3777
  return brushes[(modA ? 1 : 0) + (modB ? 2 : 0)];
3664
3778
  }
3665
3779
  function addShape(drawable, cur) {
3666
- const sameShape = (s) => s.orig === cur.orig && s.dest === cur.dest;
3667
- const similar = drawable.shapes.find(sameShape);
3780
+ const similar = drawable.shapes.find((s) => sameEndpoints(s, cur));
3668
3781
  if (similar)
3669
- drawable.shapes = drawable.shapes.filter((s) => !sameShape(s));
3670
- if (!similar || similar.brush !== cur.brush)
3782
+ drawable.shapes = drawable.shapes.filter((s) => !sameEndpoints(s, cur));
3783
+ if (!similar || !sameColor(similar, cur))
3671
3784
  drawable.shapes.push({
3672
3785
  orig: cur.orig,
3673
3786
  dest: cur.dest,
@@ -3680,7 +3793,7 @@ function onChange(drawable) {
3680
3793
  drawable.onChange(drawable.shapes);
3681
3794
  }
3682
3795
 
3683
- // node_modules/.pnpm/chessground@9.2.1/node_modules/chessground/dist/drag.js
3796
+ // node_modules/.pnpm/@lichess-org+chessground@9.8.5/node_modules/@lichess-org/chessground/dist/drag.js
3684
3797
  function start2(s, e) {
3685
3798
  if (!(s.trustAllEvents || e.isTrusted))
3686
3799
  return;
@@ -3693,7 +3806,7 @@ function start2(s, e) {
3693
3806
  return;
3694
3807
  const piece = s.pieces.get(orig);
3695
3808
  const previouslySelected = s.selected;
3696
- if (!previouslySelected && s.drawable.enabled && (s.drawable.eraseOnClick || !piece || piece.color !== s.turnColor))
3809
+ if (!previouslySelected && s.drawable.enabled && (s.drawable.eraseOnMovablePieceClick || !piece || piece.color !== s.turnColor))
3697
3810
  clear(s);
3698
3811
  if (e.cancelable !== false && (!e.touches || s.blockTouchScroll || piece || previouslySelected || pieceCloseTo(s, position)))
3699
3812
  e.preventDefault();
@@ -3739,7 +3852,7 @@ function start2(s, e) {
3739
3852
  s.dom.redraw();
3740
3853
  }
3741
3854
  function pieceCloseTo(s, pos) {
3742
- const asWhite = whitePov(s), bounds = s.dom.bounds(), radiusSq = Math.pow(bounds.width / 8, 2);
3855
+ const asWhite = whitePov(s), bounds = s.dom.bounds(), radiusSq = Math.pow(s.touchIgnoreRadius * bounds.width / 16, 2) * 2;
3743
3856
  for (const key of s.pieces.keys()) {
3744
3857
  const center = computeSquareCenter(key, asWhite, bounds);
3745
3858
  if (distanceSq(center, pos) <= radiusSq)
@@ -3768,11 +3881,10 @@ function dragNewPiece(s, piece, e, force) {
3768
3881
  }
3769
3882
  function processDrag(s) {
3770
3883
  requestAnimationFrame(() => {
3771
- var _a;
3772
3884
  const cur = s.draggable.current;
3773
3885
  if (!cur)
3774
3886
  return;
3775
- if ((_a = s.animation.current) === null || _a === void 0 ? void 0 : _a.plan.anims.has(cur.orig))
3887
+ if (s.animation.current?.plan.anims.has(cur.orig))
3776
3888
  s.animation.current = void 0;
3777
3889
  const origPiece = s.pieces.get(cur.orig);
3778
3890
  if (!origPiece || !samePiece(origPiece, cur.piece))
@@ -3867,7 +3979,7 @@ function pieceElementByKey(s, key) {
3867
3979
  return;
3868
3980
  }
3869
3981
 
3870
- // node_modules/.pnpm/chessground@9.2.1/node_modules/chessground/dist/explosion.js
3982
+ // node_modules/.pnpm/@lichess-org+chessground@9.8.5/node_modules/@lichess-org/chessground/dist/explosion.js
3871
3983
  function explosion(state, keys) {
3872
3984
  state.exploding = { stage: 1, keys };
3873
3985
  state.dom.redraw();
@@ -3886,7 +3998,7 @@ function setStage(state, stage) {
3886
3998
  }
3887
3999
  }
3888
4000
 
3889
- // node_modules/.pnpm/chessground@9.2.1/node_modules/chessground/dist/api.js
4001
+ // node_modules/.pnpm/@lichess-org+chessground@9.8.5/node_modules/@lichess-org/chessground/dist/api.js
3890
4002
  function start3(state, redrawAll) {
3891
4003
  function toggleOrientation2() {
3892
4004
  toggleOrientation(state);
@@ -3960,7 +4072,7 @@ function start3(state, redrawAll) {
3960
4072
  render((state2) => state2.drawable.autoShapes = shapes, state);
3961
4073
  },
3962
4074
  setShapes(shapes) {
3963
- render((state2) => state2.drawable.shapes = shapes, state);
4075
+ render((state2) => state2.drawable.shapes = shapes.slice(), state);
3964
4076
  },
3965
4077
  getKeyAtDomPos(pos) {
3966
4078
  return getKeyAtDomPos(pos, whitePov(state), state.dom.bounds());
@@ -3977,7 +4089,7 @@ function start3(state, redrawAll) {
3977
4089
  };
3978
4090
  }
3979
4091
 
3980
- // node_modules/.pnpm/chessground@9.2.1/node_modules/chessground/dist/state.js
4092
+ // node_modules/.pnpm/@lichess-org+chessground@9.8.5/node_modules/@lichess-org/chessground/dist/state.js
3981
4093
  function defaults() {
3982
4094
  return {
3983
4095
  pieces: read(initial),
@@ -3991,6 +4103,7 @@ function defaults() {
3991
4103
  disableContextMenu: false,
3992
4104
  addPieceZIndex: false,
3993
4105
  blockTouchScroll: false,
4106
+ touchIgnoreRadius: 1,
3994
4107
  pieceKey: false,
3995
4108
  trustAllEvents: false,
3996
4109
  highlight: {
@@ -4012,6 +4125,7 @@ function defaults() {
4012
4125
  enabled: true,
4013
4126
  showDests: true,
4014
4127
  castle: true,
4128
+ additionalPremoveRequirements: (_) => true,
4015
4129
  events: {}
4016
4130
  },
4017
4131
  predroppable: {
@@ -4043,7 +4157,7 @@ function defaults() {
4043
4157
  visible: true,
4044
4158
  // can view
4045
4159
  defaultSnapToValidMove: true,
4046
- eraseOnClick: true,
4160
+ eraseOnMovablePieceClick: true,
4047
4161
  shapes: [],
4048
4162
  autoShapes: [],
4049
4163
  brushes: {
@@ -4062,7 +4176,8 @@ function defaults() {
4062
4176
  },
4063
4177
  purple: { key: "purple", color: "#68217a", opacity: 0.65, lineWidth: 10 },
4064
4178
  pink: { key: "pink", color: "#ee2080", opacity: 0.5, lineWidth: 10 },
4065
- white: { key: "white", color: "white", opacity: 1, lineWidth: 10 }
4179
+ white: { key: "white", color: "white", opacity: 1, lineWidth: 10 },
4180
+ paleWhite: { key: "pwhite", color: "white", opacity: 0.6, lineWidth: 10 }
4066
4181
  },
4067
4182
  prevSvgHash: ""
4068
4183
  },
@@ -4070,118 +4185,128 @@ function defaults() {
4070
4185
  };
4071
4186
  }
4072
4187
 
4073
- // node_modules/.pnpm/chessground@9.2.1/node_modules/chessground/dist/svg.js
4074
- var hilites = {
4075
- hilitePrimary: { key: "hilitePrimary", color: "#3291ff", opacity: 1, lineWidth: 1 },
4076
- hiliteWhite: { key: "hiliteWhite", color: "#ffffff", opacity: 1, lineWidth: 1 }
4077
- };
4188
+ // node_modules/.pnpm/@lichess-org+chessground@9.8.5/node_modules/@lichess-org/chessground/dist/svg.js
4078
4189
  function createDefs() {
4079
4190
  const defs = createElement("defs");
4080
4191
  const filter = setAttributes(createElement("filter"), { id: "cg-filter-blur" });
4081
- filter.appendChild(setAttributes(createElement("feGaussianBlur"), { stdDeviation: "0.019" }));
4192
+ filter.appendChild(setAttributes(createElement("feGaussianBlur"), { stdDeviation: "0.013" }));
4082
4193
  defs.appendChild(filter);
4083
4194
  return defs;
4084
4195
  }
4085
- function renderSvg(state, shapesEl, customsEl) {
4086
- var _a;
4196
+ function renderSvg(state, els) {
4087
4197
  const d = state.drawable, curD = d.current, cur = curD && curD.mouseSq ? curD : void 0, dests = /* @__PURE__ */ new Map(), bounds = state.dom.bounds(), nonPieceAutoShapes = d.autoShapes.filter((autoShape) => !autoShape.piece);
4088
4198
  for (const s of d.shapes.concat(nonPieceAutoShapes).concat(cur ? [cur] : [])) {
4089
4199
  if (!s.dest)
4090
4200
  continue;
4091
- const sources = (_a = dests.get(s.dest)) !== null && _a !== void 0 ? _a : /* @__PURE__ */ new Set(), from = pos2user(orient(key2pos(s.orig), state.orientation), bounds), to = pos2user(orient(key2pos(s.dest), state.orientation), bounds);
4201
+ const sources = dests.get(s.dest) ?? /* @__PURE__ */ new Set(), from = pos2user(orient(key2pos(s.orig), state.orientation), bounds), to = pos2user(orient(key2pos(s.dest), state.orientation), bounds);
4092
4202
  sources.add(moveAngle(from, to));
4093
4203
  dests.set(s.dest, sources);
4094
4204
  }
4095
- const shapes = d.shapes.concat(nonPieceAutoShapes).map((s) => {
4096
- return {
4205
+ const shapes = [];
4206
+ const pendingEraseIdx = cur ? d.shapes.findIndex((s) => sameEndpoints(s, cur) && sameColor(s, cur)) : -1;
4207
+ for (const [idx, s] of d.shapes.concat(nonPieceAutoShapes).entries()) {
4208
+ const isPendingErase = pendingEraseIdx !== -1 && pendingEraseIdx === idx;
4209
+ shapes.push({
4097
4210
  shape: s,
4098
4211
  current: false,
4099
- hash: shapeHash(s, isShort(s.dest, dests), false, bounds)
4100
- };
4101
- });
4102
- if (cur)
4212
+ pendingErase: isPendingErase,
4213
+ hash: shapeHash(s, isShort(s.dest, dests), false, bounds, isPendingErase)
4214
+ });
4215
+ }
4216
+ if (cur && pendingEraseIdx === -1)
4103
4217
  shapes.push({
4104
4218
  shape: cur,
4105
4219
  current: true,
4106
- hash: shapeHash(cur, isShort(cur.dest, dests), true, bounds)
4220
+ hash: shapeHash(cur, isShort(cur.dest, dests), true, bounds, false),
4221
+ pendingErase: false
4107
4222
  });
4108
4223
  const fullHash = shapes.map((sc) => sc.hash).join(";");
4109
4224
  if (fullHash === state.drawable.prevSvgHash)
4110
4225
  return;
4111
4226
  state.drawable.prevSvgHash = fullHash;
4112
- const defsEl = shapesEl.querySelector("defs");
4113
- syncDefs(d, shapes, defsEl);
4114
- syncShapes(shapes, shapesEl.querySelector("g"), customsEl.querySelector("g"), (s) => renderShape(state, s, d.brushes, dests, bounds));
4115
- }
4116
- function syncDefs(d, shapes, defsEl) {
4117
- var _a;
4118
- const brushes2 = /* @__PURE__ */ new Map();
4119
- let brush;
4120
- for (const s of shapes.filter((s2) => s2.shape.dest && s2.shape.brush)) {
4121
- brush = makeCustomBrush(d.brushes[s.shape.brush], s.shape.modifiers);
4122
- if ((_a = s.shape.modifiers) === null || _a === void 0 ? void 0 : _a.hilite)
4123
- brushes2.set(hilite(brush).key, hilite(brush));
4124
- brushes2.set(brush.key, brush);
4125
- }
4126
- const keysInDom = /* @__PURE__ */ new Set();
4127
- let el = defsEl.firstElementChild;
4128
- while (el) {
4129
- keysInDom.add(el.getAttribute("cgKey"));
4130
- el = el.nextElementSibling;
4131
- }
4132
- for (const [key, brush2] of brushes2.entries()) {
4133
- if (!keysInDom.has(key))
4134
- defsEl.appendChild(renderMarker(brush2));
4135
- }
4136
- }
4137
- function syncShapes(syncables, shapes, customs, renderShape3) {
4138
- const hashesInDom = /* @__PURE__ */ new Map();
4139
- for (const sc of syncables)
4140
- hashesInDom.set(sc.hash, false);
4141
- for (const root of [shapes, customs]) {
4142
- const toRemove = [];
4143
- let el = root.firstElementChild, elHash;
4227
+ syncDefs(d, shapes, els);
4228
+ syncShapes(shapes, els, (s) => renderShape(state, s, d.brushes, dests, bounds));
4229
+ }
4230
+ function syncDefs(d, shapes, els) {
4231
+ for (const shapesEl of [els.shapes, els.shapesBelow]) {
4232
+ const defsEl = shapesEl.querySelector("defs");
4233
+ const thisPlane = shapes.filter((s) => shapesEl === els.shapesBelow === !!s.shape.below);
4234
+ const brushes2 = /* @__PURE__ */ new Map();
4235
+ for (const s of thisPlane.filter((s2) => s2.shape.dest && s2.shape.brush)) {
4236
+ const brush = makeCustomBrush(d.brushes[s.shape.brush], s.shape.modifiers);
4237
+ const { key, color } = hiliteOf(s.shape);
4238
+ if (key && color)
4239
+ brushes2.set(key, { key, color, opacity: 1, lineWidth: 1 });
4240
+ brushes2.set(brush.key, brush);
4241
+ }
4242
+ const keysInDom = /* @__PURE__ */ new Set();
4243
+ let el = defsEl.firstElementChild;
4144
4244
  while (el) {
4145
- elHash = el.getAttribute("cgHash");
4146
- if (hashesInDom.has(elHash))
4147
- hashesInDom.set(elHash, true);
4148
- else
4149
- toRemove.push(el);
4245
+ keysInDom.add(el.getAttribute("cgKey"));
4150
4246
  el = el.nextElementSibling;
4151
4247
  }
4152
- for (const el2 of toRemove)
4153
- root.removeChild(el2);
4154
- }
4155
- for (const sc of syncables.filter((s) => !hashesInDom.get(s.hash))) {
4156
- for (const svg of renderShape3(sc)) {
4157
- if (svg.isCustom)
4158
- customs.appendChild(svg.el);
4159
- else
4160
- shapes.appendChild(svg.el);
4248
+ for (const [key, brush] of brushes2.entries()) {
4249
+ if (!keysInDom.has(key))
4250
+ defsEl.appendChild(renderMarker(brush));
4251
+ }
4252
+ }
4253
+ }
4254
+ function syncShapes(shapes, els, renderShape3) {
4255
+ for (const [shapesEl, customEl] of [
4256
+ [els.shapes, els.custom],
4257
+ [els.shapesBelow, els.customBelow]
4258
+ ]) {
4259
+ const [shapesG, customG] = [shapesEl, customEl].map((el) => el.querySelector("g"));
4260
+ const thisPlane = shapes.filter((s) => shapesEl === els.shapesBelow === !!s.shape.below);
4261
+ const hashesInDom = /* @__PURE__ */ new Map();
4262
+ for (const sc of thisPlane)
4263
+ hashesInDom.set(sc.hash, false);
4264
+ for (const root of [shapesG, customG]) {
4265
+ const toRemove = [];
4266
+ let el = root.firstElementChild, elHash;
4267
+ while (el) {
4268
+ elHash = el.getAttribute("cgHash");
4269
+ if (hashesInDom.has(elHash))
4270
+ hashesInDom.set(elHash, true);
4271
+ else
4272
+ toRemove.push(el);
4273
+ el = el.nextElementSibling;
4274
+ }
4275
+ for (const el2 of toRemove)
4276
+ root.removeChild(el2);
4277
+ }
4278
+ for (const sc of thisPlane.filter((s) => !hashesInDom.get(s.hash))) {
4279
+ for (const svg of renderShape3(sc)) {
4280
+ if (svg.isCustom)
4281
+ customG.appendChild(svg.el);
4282
+ else
4283
+ shapesG.appendChild(svg.el);
4284
+ }
4161
4285
  }
4162
4286
  }
4163
4287
  }
4164
- function shapeHash({ orig, dest, brush, piece, modifiers, customSvg, label }, shorten, current, bounds) {
4165
- var _a, _b;
4288
+ function shapeHash({ orig, dest, brush, piece, modifiers, customSvg, label, below }, shorten, current, bounds, pendingErase) {
4166
4289
  return [
4167
4290
  bounds.width,
4168
4291
  bounds.height,
4169
4292
  current,
4293
+ pendingErase && "pendingErase",
4170
4294
  orig,
4171
4295
  dest,
4172
4296
  brush,
4173
4297
  shorten && "-",
4174
4298
  piece && pieceHash(piece),
4175
4299
  modifiers && modifiersHash(modifiers),
4176
- customSvg && `custom-${textHash(customSvg.html)},${(_b = (_a = customSvg.center) === null || _a === void 0 ? void 0 : _a[0]) !== null && _b !== void 0 ? _b : "o"}`,
4177
- label && `label-${textHash(label.text)}`
4300
+ customSvg && `custom-${textHash(customSvg.html)},${customSvg.center?.[0] ?? "o"}`,
4301
+ label && `label-${textHash(label.text)}`,
4302
+ below && "below"
4178
4303
  ].filter((x) => x).join(",");
4179
4304
  }
4180
4305
  function pieceHash(piece) {
4181
4306
  return [piece.color, piece.role, piece.scale].filter((x) => x).join(",");
4182
4307
  }
4183
4308
  function modifiersHash(m) {
4184
- return [m.lineWidth, m.hilite && "*"].filter((x) => x).join(",");
4309
+ return [m.lineWidth, m.hilite].filter((x) => x).join(",");
4185
4310
  }
4186
4311
  function textHash(s) {
4187
4312
  let h2 = 0;
@@ -4190,25 +4315,24 @@ function textHash(s) {
4190
4315
  }
4191
4316
  return h2.toString();
4192
4317
  }
4193
- function renderShape(state, { shape, current, hash: hash2 }, brushes2, dests, bounds) {
4194
- var _a, _b;
4318
+ function renderShape(state, { shape, current, pendingErase, hash: hash2 }, brushes2, dests, bounds) {
4195
4319
  const from = pos2user(orient(key2pos(shape.orig), state.orientation), bounds), to = shape.dest ? pos2user(orient(key2pos(shape.dest), state.orientation), bounds) : from, brush = shape.brush && makeCustomBrush(brushes2[shape.brush], shape.modifiers), slots = dests.get(shape.dest), svgs = [];
4196
4320
  if (brush) {
4197
4321
  const el = setAttributes(createElement("g"), { cgHash: hash2 });
4198
4322
  svgs.push({ el });
4199
4323
  if (from[0] !== to[0] || from[1] !== to[1])
4200
- el.appendChild(renderArrow(shape, brush, from, to, current, isShort(shape.dest, dests)));
4324
+ el.appendChild(renderArrow(shape, brush, from, to, current, isShort(shape.dest, dests), pendingErase));
4201
4325
  else
4202
- el.appendChild(renderCircle(brushes2[shape.brush], from, current, bounds));
4326
+ el.appendChild(renderCircle(brushes2[shape.brush], from, current, bounds, pendingErase));
4203
4327
  }
4204
4328
  if (shape.label) {
4205
4329
  const label = shape.label;
4206
- (_a = label.fill) !== null && _a !== void 0 ? _a : label.fill = shape.brush && brushes2[shape.brush].color;
4330
+ label.fill ?? (label.fill = shape.brush && brushes2[shape.brush].color);
4207
4331
  const corner = shape.brush ? void 0 : "tr";
4208
4332
  svgs.push({ el: renderLabel(label, hash2, from, to, slots, corner), isCustom: true });
4209
4333
  }
4210
4334
  if (shape.customSvg) {
4211
- const on = (_b = shape.customSvg.center) !== null && _b !== void 0 ? _b : "orig";
4335
+ const on = shape.customSvg.center ?? "orig";
4212
4336
  const [x, y] = on === "label" ? labelCoords(from, to, slots).map((c) => c - 0.5) : on === "dest" ? to : from;
4213
4337
  const el = setAttributes(createElement("g"), { transform: `translate(${x},${y})`, cgHash: hash2 });
4214
4338
  el.innerHTML = `<svg width="1" height="1" viewBox="0 0 100 100">${shape.customSvg.html}</svg>`;
@@ -4216,41 +4340,37 @@ function renderShape(state, { shape, current, hash: hash2 }, brushes2, dests, bo
4216
4340
  }
4217
4341
  return svgs;
4218
4342
  }
4219
- function renderCircle(brush, at, current, bounds) {
4343
+ function renderCircle(brush, at, current, bounds, pendingErase) {
4220
4344
  const widths = circleWidth(), radius = (bounds.width + bounds.height) / (4 * Math.max(bounds.width, bounds.height));
4221
4345
  return setAttributes(createElement("circle"), {
4222
4346
  stroke: brush.color,
4223
4347
  "stroke-width": widths[current ? 0 : 1],
4224
4348
  fill: "none",
4225
- opacity: opacity(brush, current),
4349
+ opacity: opacity(brush, current, pendingErase),
4226
4350
  cx: at[0],
4227
4351
  cy: at[1],
4228
4352
  r: radius - widths[1] / 2
4229
4353
  });
4230
4354
  }
4231
- function hilite(brush) {
4232
- return ["#ffffff", "#fff", "white"].includes(brush.color) ? hilites["hilitePrimary"] : hilites["hiliteWhite"];
4233
- }
4234
- function renderArrow(s, brush, from, to, current, shorten) {
4235
- var _a;
4355
+ function renderArrow(s, brush, from, to, current, shorten, pendingErase) {
4236
4356
  function renderLine(isHilite) {
4237
- var _a2;
4238
4357
  const m = arrowMargin(shorten && !current), dx = to[0] - from[0], dy = to[1] - from[1], angle = Math.atan2(dy, dx), xo = Math.cos(angle) * m, yo = Math.sin(angle) * m;
4358
+ const hilite = hiliteOf(s);
4239
4359
  return setAttributes(createElement("line"), {
4240
- stroke: isHilite ? hilite(brush).color : brush.color,
4241
- "stroke-width": lineWidth(brush, current) + (isHilite ? 0.04 : 0),
4360
+ stroke: isHilite ? hilite.color : brush.color,
4361
+ "stroke-width": lineWidth(brush, current) * (isHilite ? 1.14 : 1),
4242
4362
  "stroke-linecap": "round",
4243
- "marker-end": `url(#arrowhead-${isHilite ? hilite(brush).key : brush.key})`,
4244
- opacity: ((_a2 = s.modifiers) === null || _a2 === void 0 ? void 0 : _a2.hilite) ? 1 : opacity(brush, current),
4363
+ "marker-end": `url(#arrowhead-${isHilite ? hilite.key : brush.key})`,
4364
+ opacity: s.modifiers?.hilite && !pendingErase ? 1 : opacity(brush, current, pendingErase),
4245
4365
  x1: from[0],
4246
4366
  y1: from[1],
4247
4367
  x2: to[0] - xo,
4248
4368
  y2: to[1] - yo
4249
4369
  });
4250
4370
  }
4251
- if (!((_a = s.modifiers) === null || _a === void 0 ? void 0 : _a.hilite))
4371
+ if (!s.modifiers?.hilite)
4252
4372
  return renderLine(false);
4253
- const g = createElement("g");
4373
+ const g = setAttributes(createElement("g"), { opacity: brush.opacity });
4254
4374
  const blurred = setAttributes(createElement("g"), { filter: "url(#cg-filter-blur)" });
4255
4375
  blurred.appendChild(filterBox(from, to));
4256
4376
  blurred.appendChild(renderLine(true));
@@ -4276,7 +4396,6 @@ function renderMarker(brush) {
4276
4396
  return marker;
4277
4397
  }
4278
4398
  function renderLabel(label, hash2, from, to, slots, corner) {
4279
- var _a;
4280
4399
  const labelSize = 0.4, fontSize = labelSize * 0.75 ** label.text.length, at = labelCoords(from, to, slots), cornerOff = corner === "tr" ? 0.4 : 0, g = setAttributes(createElement("g"), {
4281
4400
  transform: `translate(${at[0] + cornerOff},${at[1] - cornerOff})`,
4282
4401
  cgHash: hash2
@@ -4286,7 +4405,7 @@ function renderLabel(label, hash2, from, to, slots, corner) {
4286
4405
  "fill-opacity": corner ? 1 : 0.8,
4287
4406
  "stroke-opacity": corner ? 1 : 0.7,
4288
4407
  "stroke-width": 0.03,
4289
- fill: (_a = label.fill) !== null && _a !== void 0 ? _a : "#666",
4408
+ fill: label.fill ?? "#666",
4290
4409
  stroke: "white"
4291
4410
  }));
4292
4411
  const labelEl = setAttributes(createElement("text"), {
@@ -4330,8 +4449,12 @@ function circleWidth() {
4330
4449
  function lineWidth(brush, current) {
4331
4450
  return (brush.lineWidth || 10) * (current ? 0.85 : 1) / 64;
4332
4451
  }
4333
- function opacity(brush, current) {
4334
- return (brush.opacity || 1) * (current ? 0.9 : 1);
4452
+ function hiliteOf(shape) {
4453
+ const hilite = shape.modifiers?.hilite;
4454
+ return { key: hilite && `hilite-${hilite.replace("#", "")}`, color: hilite };
4455
+ }
4456
+ function opacity(brush, current, pendingErase) {
4457
+ return (brush.opacity || 1) * (pendingErase ? 0.6 : current ? 0.9 : 1);
4335
4458
  }
4336
4459
  function arrowMargin(shorten) {
4337
4460
  return (shorten ? 20 : 10) / 64;
@@ -4379,7 +4502,7 @@ function labelCoords(from, to, slots) {
4379
4502
  return [from[0] - Math.cos(angle) * mag, from[1] - Math.sin(angle) * mag].map((c) => c + 0.5);
4380
4503
  }
4381
4504
 
4382
- // node_modules/.pnpm/chessground@9.2.1/node_modules/chessground/dist/wrap.js
4505
+ // node_modules/.pnpm/@lichess-org+chessground@9.8.5/node_modules/@lichess-org/chessground/dist/wrap.js
4383
4506
  function renderWrap(element, s) {
4384
4507
  element.innerHTML = "";
4385
4508
  element.classList.add("cg-wrap");
@@ -4390,26 +4513,19 @@ function renderWrap(element, s) {
4390
4513
  element.appendChild(container);
4391
4514
  const board = createEl("cg-board");
4392
4515
  container.appendChild(board);
4393
- let svg;
4394
- let customSvg;
4516
+ let shapesBelow;
4517
+ let shapes;
4518
+ let customBelow;
4519
+ let custom;
4395
4520
  let autoPieces;
4396
4521
  if (s.drawable.visible) {
4397
- svg = setAttributes(createElement("svg"), {
4398
- class: "cg-shapes",
4399
- viewBox: "-4 -4 8 8",
4400
- preserveAspectRatio: "xMidYMid slice"
4401
- });
4402
- svg.appendChild(createDefs());
4403
- svg.appendChild(createElement("g"));
4404
- customSvg = setAttributes(createElement("svg"), {
4405
- class: "cg-custom-svgs",
4406
- viewBox: "-3.5 -3.5 8 8",
4407
- preserveAspectRatio: "xMidYMid slice"
4408
- });
4409
- customSvg.appendChild(createElement("g"));
4522
+ [shapesBelow, shapes] = ["cg-shapes-below", "cg-shapes"].map((cls) => svgContainer(cls, true));
4523
+ [customBelow, custom] = ["cg-custom-below", "cg-custom-svgs"].map((cls) => svgContainer(cls, false));
4410
4524
  autoPieces = createEl("cg-auto-pieces");
4411
- container.appendChild(svg);
4412
- container.appendChild(customSvg);
4525
+ container.appendChild(shapesBelow);
4526
+ container.appendChild(customBelow);
4527
+ container.appendChild(shapes);
4528
+ container.appendChild(custom);
4413
4529
  container.appendChild(autoPieces);
4414
4530
  }
4415
4531
  if (s.coordinates) {
@@ -4429,15 +4545,18 @@ function renderWrap(element, s) {
4429
4545
  setVisible(ghost, false);
4430
4546
  container.appendChild(ghost);
4431
4547
  }
4432
- return {
4433
- board,
4434
- container,
4435
- wrap: element,
4436
- ghost,
4437
- svg,
4438
- customSvg,
4439
- autoPieces
4440
- };
4548
+ return { board, container, wrap: element, ghost, shapes, shapesBelow, custom, customBelow, autoPieces };
4549
+ }
4550
+ function svgContainer(cls, isShapes) {
4551
+ const svg = setAttributes(createElement("svg"), {
4552
+ class: cls,
4553
+ viewBox: isShapes ? "-4 -4 8 8" : "-3.5 -3.5 8 8",
4554
+ preserveAspectRatio: "xMidYMid slice"
4555
+ });
4556
+ if (isShapes)
4557
+ svg.appendChild(createDefs());
4558
+ svg.appendChild(createElement("g"));
4559
+ return svg;
4441
4560
  }
4442
4561
  function renderCoords(elems, className) {
4443
4562
  const el = createEl("coords", className);
@@ -4450,7 +4569,7 @@ function renderCoords(elems, className) {
4450
4569
  return el;
4451
4570
  }
4452
4571
 
4453
- // node_modules/.pnpm/chessground@9.2.1/node_modules/chessground/dist/drop.js
4572
+ // node_modules/.pnpm/@lichess-org+chessground@9.8.5/node_modules/@lichess-org/chessground/dist/drop.js
4454
4573
  function drop(s, e) {
4455
4574
  if (!s.dropmode.active)
4456
4575
  return;
@@ -4467,7 +4586,7 @@ function drop(s, e) {
4467
4586
  s.dom.redraw();
4468
4587
  }
4469
4588
 
4470
- // node_modules/.pnpm/chessground@9.2.1/node_modules/chessground/dist/events.js
4589
+ // node_modules/.pnpm/@lichess-org+chessground@9.8.5/node_modules/@lichess-org/chessground/dist/events.js
4471
4590
  function bindBoard(s, onResize) {
4472
4591
  const boardEl = s.dom.elements.board;
4473
4592
  if ("ResizeObserver" in window)
@@ -4529,7 +4648,7 @@ var dragOrDraw = (s, withDrag, withDraw) => (e) => {
4529
4648
  withDrag(s, e);
4530
4649
  };
4531
4650
 
4532
- // node_modules/.pnpm/chessground@9.2.1/node_modules/chessground/dist/render.js
4651
+ // node_modules/.pnpm/@lichess-org+chessground@9.8.5/node_modules/@lichess-org/chessground/dist/render.js
4533
4652
  function render2(s) {
4534
4653
  const asWhite = whitePov(s), posToTranslate2 = posToTranslate(s.dom.bounds()), boardEl = s.dom.elements.board, pieces = s.pieces, curAnim = s.animation.current, anims = curAnim ? curAnim.plan.anims : /* @__PURE__ */ new Map(), fadings = curAnim ? curAnim.plan.fadings : /* @__PURE__ */ new Map(), curDrag = s.draggable.current, squares = computeSquareClasses(s), samePieces = /* @__PURE__ */ new Set(), sameSquares = /* @__PURE__ */ new Set(), movedPieces = /* @__PURE__ */ new Map(), movedSquares = /* @__PURE__ */ new Map();
4535
4654
  let k, el, pieceAtKey, elPieceName, anim2, fading, pMvdset, pMvd, sMvdset, sMvd;
@@ -4655,7 +4774,6 @@ function renderResized(s) {
4655
4774
  }
4656
4775
  }
4657
4776
  function updateBounds(s) {
4658
- var _a, _b;
4659
4777
  const bounds = s.dom.elements.wrap.getBoundingClientRect();
4660
4778
  const container = s.dom.elements.container;
4661
4779
  const ratio = bounds.height / bounds.width;
@@ -4664,8 +4782,8 @@ function updateBounds(s) {
4664
4782
  container.style.width = width + "px";
4665
4783
  container.style.height = height + "px";
4666
4784
  s.dom.bounds.clear();
4667
- (_a = s.addDimensionsCssVarsTo) === null || _a === void 0 ? void 0 : _a.style.setProperty("---cg-width", width + "px");
4668
- (_b = s.addDimensionsCssVarsTo) === null || _b === void 0 ? void 0 : _b.style.setProperty("---cg-height", height + "px");
4785
+ s.addDimensionsCssVarsTo?.style.setProperty("---cg-width", width + "px");
4786
+ s.addDimensionsCssVarsTo?.style.setProperty("---cg-height", height + "px");
4669
4787
  }
4670
4788
  var isPieceNode = (el) => el.tagName === "PIECE";
4671
4789
  var isSquareNode = (el) => el.tagName === "SQUARE";
@@ -4681,7 +4799,6 @@ function posZIndex(pos, asWhite) {
4681
4799
  }
4682
4800
  var pieceNameOf = (piece) => `${piece.color} ${piece.role}`;
4683
4801
  function computeSquareClasses(s) {
4684
- var _a, _b, _c;
4685
4802
  const squares = /* @__PURE__ */ new Map();
4686
4803
  if (s.lastMove && s.highlight.lastMove)
4687
4804
  for (const k of s.lastMove) {
@@ -4692,12 +4809,12 @@ function computeSquareClasses(s) {
4692
4809
  if (s.selected) {
4693
4810
  addSquare(squares, s.selected, "selected");
4694
4811
  if (s.movable.showDests) {
4695
- const dests = (_a = s.movable.dests) === null || _a === void 0 ? void 0 : _a.get(s.selected);
4812
+ const dests = s.movable.dests?.get(s.selected);
4696
4813
  if (dests)
4697
4814
  for (const k of dests) {
4698
4815
  addSquare(squares, k, "move-dest" + (s.pieces.has(k) ? " oc" : ""));
4699
4816
  }
4700
- const pDests = (_c = (_b = s.premovable.customDests) === null || _b === void 0 ? void 0 : _b.get(s.selected)) !== null && _c !== void 0 ? _c : s.premovable.dests;
4817
+ const pDests = s.premovable.customDests?.get(s.selected) ?? s.premovable.dests;
4701
4818
  if (pDests)
4702
4819
  for (const k of pDests) {
4703
4820
  addSquare(squares, k, "premove-dest" + (s.pieces.has(k) ? " oc" : ""));
@@ -4736,7 +4853,7 @@ function appendValue(map, key, value) {
4736
4853
  map.set(key, [value]);
4737
4854
  }
4738
4855
 
4739
- // node_modules/.pnpm/chessground@9.2.1/node_modules/chessground/dist/sync.js
4856
+ // node_modules/.pnpm/@lichess-org+chessground@9.8.5/node_modules/@lichess-org/chessground/dist/sync.js
4740
4857
  function syncShapes2(shapes, root, renderShape3) {
4741
4858
  const hashesInDom = /* @__PURE__ */ new Map(), toRemove = [];
4742
4859
  for (const sc of shapes)
@@ -4758,33 +4875,32 @@ function syncShapes2(shapes, root, renderShape3) {
4758
4875
  }
4759
4876
  }
4760
4877
 
4761
- // node_modules/.pnpm/chessground@9.2.1/node_modules/chessground/dist/autoPieces.js
4878
+ // node_modules/.pnpm/@lichess-org+chessground@9.8.5/node_modules/@lichess-org/chessground/dist/autoPieces.js
4762
4879
  function render3(state, autoPieceEl) {
4763
4880
  const autoPieces = state.drawable.autoShapes.filter((autoShape) => autoShape.piece);
4764
4881
  const autoPieceShapes = autoPieces.map((s) => {
4765
4882
  return {
4766
4883
  shape: s,
4767
4884
  hash: hash(s),
4768
- current: false
4885
+ current: false,
4886
+ pendingErase: false
4769
4887
  };
4770
4888
  });
4771
4889
  syncShapes2(autoPieceShapes, autoPieceEl, (shape) => renderShape2(state, shape, state.dom.bounds()));
4772
4890
  }
4773
4891
  function renderResized2(state) {
4774
- var _a;
4775
4892
  const asWhite = whitePov(state), posToTranslate2 = posToTranslate(state.dom.bounds());
4776
- let el = (_a = state.dom.elements.autoPieces) === null || _a === void 0 ? void 0 : _a.firstChild;
4893
+ let el = state.dom.elements.autoPieces?.firstChild;
4777
4894
  while (el) {
4778
4895
  translateAndScale(el, posToTranslate2(key2pos(el.cgKey), asWhite), el.cgScale);
4779
4896
  el = el.nextSibling;
4780
4897
  }
4781
4898
  }
4782
4899
  function renderShape2(state, { shape, hash: hash2 }, bounds) {
4783
- var _a, _b, _c;
4784
4900
  const orig = shape.orig;
4785
- const role = (_a = shape.piece) === null || _a === void 0 ? void 0 : _a.role;
4786
- const color = (_b = shape.piece) === null || _b === void 0 ? void 0 : _b.color;
4787
- const scale = (_c = shape.piece) === null || _c === void 0 ? void 0 : _c.scale;
4901
+ const role = shape.piece?.role;
4902
+ const color = shape.piece?.color;
4903
+ const scale = shape.piece?.scale;
4788
4904
  const pieceEl = createEl("piece", `${role} ${color}`);
4789
4905
  pieceEl.setAttribute("cgHash", hash2);
4790
4906
  pieceEl.cgKey = orig;
@@ -4792,12 +4908,9 @@ function renderShape2(state, { shape, hash: hash2 }, bounds) {
4792
4908
  translateAndScale(pieceEl, posToTranslate(bounds)(key2pos(orig), whitePov(state)), scale);
4793
4909
  return pieceEl;
4794
4910
  }
4795
- var hash = (autoPiece) => {
4796
- var _a, _b, _c;
4797
- return [autoPiece.orig, (_a = autoPiece.piece) === null || _a === void 0 ? void 0 : _a.role, (_b = autoPiece.piece) === null || _b === void 0 ? void 0 : _b.color, (_c = autoPiece.piece) === null || _c === void 0 ? void 0 : _c.scale].join(",");
4798
- };
4911
+ var hash = (autoPiece) => [autoPiece.orig, autoPiece.piece?.role, autoPiece.piece?.color, autoPiece.piece?.scale].join(",");
4799
4912
 
4800
- // node_modules/.pnpm/chessground@9.2.1/node_modules/chessground/dist/chessground.js
4913
+ // node_modules/.pnpm/@lichess-org+chessground@9.8.5/node_modules/@lichess-org/chessground/dist/chessground.js
4801
4914
  function Chessground(element, config) {
4802
4915
  const maybeState = defaults();
4803
4916
  configure(maybeState, config || {});
@@ -4807,8 +4920,8 @@ function Chessground(element, config) {
4807
4920
  render2(state);
4808
4921
  if (elements.autoPieces)
4809
4922
  render3(state, elements.autoPieces);
4810
- if (!skipSvg && elements.svg)
4811
- renderSvg(state, elements.svg, elements.customSvg);
4923
+ if (!skipSvg && elements.shapes)
4924
+ renderSvg(state, elements);
4812
4925
  }, onResize = () => {
4813
4926
  updateBounds(state);
4814
4927
  renderResized(state);