next-chessground 0.7.1 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.es.js CHANGED
@@ -1,4 +1,4 @@
1
- import React, { useState, createContext, useContext } from 'react';
1
+ import React, { useState, createContext, useContext, forwardRef, useMemo } from 'react';
2
2
  import require$$1 from 'react-dom';
3
3
 
4
4
  function _defineProperty(obj, key, value) {
@@ -2181,31 +2181,15 @@ if (process.env.NODE_ENV !== 'production') {
2181
2181
  }
2182
2182
  });
2183
2183
 
2184
- var types = createCommonjsModule(function (module, exports) {
2185
-
2186
- Object.defineProperty(exports, "__esModule", {
2187
- value: true
2188
- });
2189
- exports.files = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'];
2190
- exports.ranks = [1, 2, 3, 4, 5, 6, 7, 8];
2191
- });
2192
-
2193
- var util = createCommonjsModule(function (module, exports) {
2194
-
2195
- Object.defineProperty(exports, "__esModule", {
2196
- value: true
2197
- });
2198
-
2199
-
2200
-
2201
- exports.colors = ['white', 'black'];
2202
- exports.invRanks = [8, 7, 6, 5, 4, 3, 2, 1];
2203
- exports.allKeys = Array.prototype.concat(...types.files.map(c => types.ranks.map(r => c + r)));
2204
-
2205
- exports.pos2key = pos => exports.allKeys[8 * pos[0] + pos[1] - 9];
2206
-
2207
- exports.key2pos = k => [k.charCodeAt(0) - 96, k.charCodeAt(1) - 48];
2184
+ const colors = ['white', 'black'];
2185
+ const files = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'];
2186
+ const ranks = ['1', '2', '3', '4', '5', '6', '7', '8'];
2208
2187
 
2188
+ const invRanks = [...ranks].reverse();
2189
+ const allKeys = Array.prototype.concat(...files.map(c => ranks.map(r => c + r)));
2190
+ const pos2key = pos => allKeys[8 * pos[0] + pos[1]];
2191
+ const key2pos = k => [k.charCodeAt(0) - 97, k.charCodeAt(1) - 49];
2192
+ const allPos = allKeys.map(key2pos);
2209
2193
  function memo(f) {
2210
2194
  let v;
2211
2195
 
@@ -2220,10 +2204,7 @@ function memo(f) {
2220
2204
 
2221
2205
  return ret;
2222
2206
  }
2223
-
2224
- exports.memo = memo;
2225
-
2226
- exports.timer = () => {
2207
+ const timer = () => {
2227
2208
  let startAt;
2228
2209
  return {
2229
2210
  start() {
@@ -2243,72 +2224,51 @@ exports.timer = () => {
2243
2224
 
2244
2225
  };
2245
2226
  };
2246
-
2247
- exports.opposite = c => c === 'white' ? 'black' : 'white';
2248
-
2249
- function containsX(xs, x) {
2250
- return xs !== undefined && xs.indexOf(x) !== -1;
2251
- }
2252
-
2253
- exports.containsX = containsX;
2254
-
2255
- exports.distanceSq = (pos1, pos2) => {
2256
- return Math.pow(pos1[0] - pos2[0], 2) + Math.pow(pos1[1] - pos2[1], 2);
2257
- };
2258
-
2259
- exports.samePiece = (p1, p2) => p1.role === p2.role && p1.color === p2.color;
2260
-
2261
- const posToTranslateBase = (pos, asWhite, xFactor, yFactor) => [(asWhite ? pos[0] - 1 : 8 - pos[0]) * xFactor, (asWhite ? 8 - pos[1] : pos[1] - 1) * yFactor];
2262
-
2263
- exports.posToTranslateAbs = bounds => {
2264
- const xFactor = bounds.width / 8,
2265
- yFactor = bounds.height / 8;
2266
- return (pos, asWhite) => posToTranslateBase(pos, asWhite, xFactor, yFactor);
2227
+ const opposite = c => c === 'white' ? 'black' : 'white';
2228
+ const distanceSq = (pos1, pos2) => {
2229
+ const dx = pos1[0] - pos2[0],
2230
+ dy = pos1[1] - pos2[1];
2231
+ return dx * dx + dy * dy;
2267
2232
  };
2268
-
2269
- exports.posToTranslateRel = (pos, asWhite) => posToTranslateBase(pos, asWhite, 100, 100);
2270
-
2271
- exports.translateAbs = (el, pos) => {
2233
+ const samePiece = (p1, p2) => p1.role === p2.role && p1.color === p2.color;
2234
+ const posToTranslate = bounds => (pos, asWhite) => [(asWhite ? pos[0] : 7 - pos[0]) * bounds.width / 8, (asWhite ? 7 - pos[1] : pos[1]) * bounds.height / 8];
2235
+ const translate = (el, pos) => {
2272
2236
  el.style.transform = `translate(${pos[0]}px,${pos[1]}px)`;
2273
2237
  };
2274
-
2275
- exports.translateRel = (el, percents) => {
2276
- el.style.transform = `translate(${percents[0]}%,${percents[1]}%)`;
2277
- };
2278
-
2279
- exports.setVisible = (el, v) => {
2238
+ const setVisible = (el, v) => {
2280
2239
  el.style.visibility = v ? 'visible' : 'hidden';
2281
2240
  };
2241
+ const eventPosition = e => {
2242
+ var _a;
2282
2243
 
2283
- exports.eventPosition = e => {
2284
2244
  if (e.clientX || e.clientX === 0) return [e.clientX, e.clientY];
2285
- if (e.touches && e.targetTouches[0]) return [e.targetTouches[0].clientX, e.targetTouches[0].clientY];
2286
- return undefined;
2245
+ if ((_a = e.targetTouches) === null || _a === void 0 ? void 0 : _a[0]) return [e.targetTouches[0].clientX, e.targetTouches[0].clientY];
2246
+ return; // touchend has no position!
2287
2247
  };
2288
-
2289
- exports.isRightButton = e => e.buttons === 2 || e.button === 2;
2290
-
2291
- exports.createEl = (tagName, className) => {
2248
+ const isRightButton = e => e.buttons === 2 || e.button === 2;
2249
+ const createEl = (tagName, className) => {
2292
2250
  const el = document.createElement(tagName);
2293
2251
  if (className) el.className = className;
2294
2252
  return el;
2295
2253
  };
2296
- });
2297
-
2298
- var premove_1 = createCommonjsModule(function (module, exports) {
2299
-
2300
- Object.defineProperty(exports, "__esModule", {
2301
- value: true
2302
- });
2254
+ function computeSquareCenter(key, asWhite, bounds) {
2255
+ const pos = key2pos(key);
2303
2256
 
2257
+ if (!asWhite) {
2258
+ pos[0] = 7 - pos[0];
2259
+ pos[1] = 7 - pos[1];
2260
+ }
2304
2261
 
2262
+ return [bounds.left + bounds.width * pos[0] / 8 + bounds.width / 16, bounds.top + bounds.height * (7 - pos[1]) / 8 + bounds.height / 16];
2263
+ }
2305
2264
 
2306
2265
  function diff(a, b) {
2307
2266
  return Math.abs(a - b);
2308
2267
  }
2309
2268
 
2310
2269
  function pawn(color) {
2311
- return (x1, y1, x2, y2) => diff(x1, x2) < 2 && (color === 'white' ? y2 === y1 + 1 || y1 <= 2 && y2 === y1 + 2 && x1 === x2 : y2 === y1 - 1 || y1 >= 7 && y2 === y1 - 2 && x1 === x2);
2270
+ return (x1, y1, x2, y2) => diff(x1, x2) < 2 && (color === 'white' ? // allow 2 squares from first two ranks, for horde
2271
+ y2 === y1 + 1 || y1 <= 1 && y2 === y1 + 2 && x1 === x2 : y2 === y1 - 1 || y1 >= 6 && y2 === y1 - 2 && x1 === x2);
2312
2272
  }
2313
2273
 
2314
2274
  const knight = (x1, y1, x2, y2) => {
@@ -2330,83 +2290,53 @@ const queen = (x1, y1, x2, y2) => {
2330
2290
  };
2331
2291
 
2332
2292
  function king(color, rookFiles, canCastle) {
2333
- return (x1, y1, x2, y2) => diff(x1, x2) < 2 && diff(y1, y2) < 2 || canCastle && y1 === y2 && y1 === (color === 'white' ? 1 : 8) && (x1 === 5 && (util.containsX(rookFiles, 1) && x2 === 3 || util.containsX(rookFiles, 8) && x2 === 7) || util.containsX(rookFiles, x2));
2293
+ return (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));
2334
2294
  }
2335
2295
 
2336
2296
  function rookFilesOf(pieces, color) {
2337
2297
  const backrank = color === 'white' ? '1' : '8';
2338
- return Object.keys(pieces).filter(key => {
2339
- const piece = pieces[key];
2340
- return key[1] === backrank && piece && piece.color === color && piece.role === 'rook';
2341
- }).map(key => util.key2pos(key)[0]);
2342
- }
2298
+ const files = [];
2343
2299
 
2344
- const allPos = util.allKeys.map(util.key2pos);
2300
+ for (const [key, piece] of pieces) {
2301
+ if (key[1] === backrank && piece.color === color && piece.role === 'rook') {
2302
+ files.push(key2pos(key)[0]);
2303
+ }
2304
+ }
2305
+
2306
+ return files;
2307
+ }
2345
2308
 
2346
2309
  function premove(pieces, key, canCastle) {
2347
- const piece = pieces[key],
2348
- pos = util.key2pos(key),
2310
+ const piece = pieces.get(key);
2311
+ if (!piece) return [];
2312
+ const pos = key2pos(key),
2349
2313
  r = piece.role,
2350
2314
  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);
2351
- return allPos.filter(pos2 => (pos[0] !== pos2[0] || pos[1] !== pos2[1]) && mobility(pos[0], pos[1], pos2[0], pos2[1])).map(util.pos2key);
2315
+ return allPos.filter(pos2 => (pos[0] !== pos2[0] || pos[1] !== pos2[1]) && mobility(pos[0], pos[1], pos2[0], pos2[1])).map(pos2key);
2352
2316
  }
2353
2317
 
2354
- exports.default = premove;
2355
- });
2356
-
2357
- var board = createCommonjsModule(function (module, exports) {
2358
-
2359
- Object.defineProperty(exports, "__esModule", {
2360
- value: true
2361
- });
2362
-
2363
-
2364
-
2365
-
2366
-
2367
2318
  function callUserFunction(f, ...args) {
2368
2319
  if (f) setTimeout(() => f(...args), 1);
2369
2320
  }
2370
-
2371
- exports.callUserFunction = callUserFunction;
2372
-
2373
2321
  function toggleOrientation(state) {
2374
- state.orientation = util.opposite(state.orientation);
2322
+ state.orientation = opposite(state.orientation);
2375
2323
  state.animation.current = state.draggable.current = state.selected = undefined;
2376
2324
  }
2377
-
2378
- exports.toggleOrientation = toggleOrientation;
2379
-
2380
- function reset(state) {
2381
- state.lastMove = undefined;
2382
- unselect(state);
2383
- unsetPremove(state);
2384
- unsetPredrop(state);
2385
- }
2386
-
2387
- exports.reset = reset;
2388
-
2389
2325
  function setPieces(state, pieces) {
2390
- for (const key in pieces) {
2391
- const piece = pieces[key];
2392
- if (piece) state.pieces[key] = piece;else delete state.pieces[key];
2326
+ for (const [key, piece] of pieces) {
2327
+ if (piece) state.pieces.set(key, piece);else state.pieces.delete(key);
2393
2328
  }
2394
2329
  }
2395
-
2396
- exports.setPieces = setPieces;
2397
-
2398
2330
  function setCheck(state, color) {
2399
2331
  state.check = undefined;
2400
2332
  if (color === true) color = state.turnColor;
2401
- if (color) for (const k in state.pieces) {
2402
- if (state.pieces[k].role === 'king' && state.pieces[k].color === color) {
2333
+ if (color) for (const [k, p] of state.pieces) {
2334
+ if (p.role === 'king' && p.color === color) {
2403
2335
  state.check = k;
2404
2336
  }
2405
2337
  }
2406
2338
  }
2407
2339
 
2408
- exports.setCheck = setCheck;
2409
-
2410
2340
  function setPremove(state, orig, dest, meta) {
2411
2341
  unsetPredrop(state);
2412
2342
  state.premovable.current = [orig, dest];
@@ -2420,8 +2350,6 @@ function unsetPremove(state) {
2420
2350
  }
2421
2351
  }
2422
2352
 
2423
- exports.unsetPremove = unsetPremove;
2424
-
2425
2353
  function setPredrop(state, role, key) {
2426
2354
  unsetPremove(state);
2427
2355
  state.predroppable.current = {
@@ -2440,47 +2368,45 @@ function unsetPredrop(state) {
2440
2368
  }
2441
2369
  }
2442
2370
 
2443
- exports.unsetPredrop = unsetPredrop;
2444
-
2445
2371
  function tryAutoCastle(state, orig, dest) {
2446
2372
  if (!state.autoCastle) return false;
2447
- const king = state.pieces[orig];
2373
+ const king = state.pieces.get(orig);
2448
2374
  if (!king || king.role !== 'king') return false;
2449
- const origPos = util.key2pos(orig);
2450
- const destPos = util.key2pos(dest);
2451
- if (origPos[1] !== 1 && origPos[1] !== 8 || origPos[1] !== destPos[1]) return false;
2375
+ const origPos = key2pos(orig);
2376
+ const destPos = key2pos(dest);
2377
+ if (origPos[1] !== 0 && origPos[1] !== 7 || origPos[1] !== destPos[1]) return false;
2452
2378
 
2453
- if (origPos[0] === 5) {
2454
- if (destPos[0] === 7) dest = util.pos2key([8, destPos[1]]);else if (destPos[0] === 3) dest = util.pos2key([1, destPos[1]]);
2379
+ if (origPos[0] === 4 && !state.pieces.has(dest)) {
2380
+ if (destPos[0] === 6) dest = pos2key([7, destPos[1]]);else if (destPos[0] === 2) dest = pos2key([0, destPos[1]]);
2455
2381
  }
2456
2382
 
2457
- const rook = state.pieces[dest];
2383
+ const rook = state.pieces.get(dest);
2458
2384
  if (!rook || rook.color !== king.color || rook.role !== 'rook') return false;
2459
- delete state.pieces[orig];
2460
- delete state.pieces[dest];
2385
+ state.pieces.delete(orig);
2386
+ state.pieces.delete(dest);
2461
2387
 
2462
2388
  if (origPos[0] < destPos[0]) {
2463
- state.pieces[util.pos2key([7, destPos[1]])] = king;
2464
- state.pieces[util.pos2key([6, destPos[1]])] = rook;
2389
+ state.pieces.set(pos2key([6, destPos[1]]), king);
2390
+ state.pieces.set(pos2key([5, destPos[1]]), rook);
2465
2391
  } else {
2466
- state.pieces[util.pos2key([3, destPos[1]])] = king;
2467
- state.pieces[util.pos2key([4, destPos[1]])] = rook;
2392
+ state.pieces.set(pos2key([2, destPos[1]]), king);
2393
+ state.pieces.set(pos2key([3, destPos[1]]), rook);
2468
2394
  }
2469
2395
 
2470
2396
  return true;
2471
2397
  }
2472
2398
 
2473
2399
  function baseMove(state, orig, dest) {
2474
- const origPiece = state.pieces[orig],
2475
- destPiece = state.pieces[dest];
2400
+ const origPiece = state.pieces.get(orig),
2401
+ destPiece = state.pieces.get(dest);
2476
2402
  if (orig === dest || !origPiece) return false;
2477
2403
  const captured = destPiece && destPiece.color !== origPiece.color ? destPiece : undefined;
2478
2404
  if (dest === state.selected) unselect(state);
2479
2405
  callUserFunction(state.events.move, orig, dest, captured);
2480
2406
 
2481
2407
  if (!tryAutoCastle(state, orig, dest)) {
2482
- state.pieces[dest] = origPiece;
2483
- delete state.pieces[orig];
2408
+ state.pieces.set(dest, origPiece);
2409
+ state.pieces.delete(orig);
2484
2410
  }
2485
2411
 
2486
2412
  state.lastMove = [orig, dest];
@@ -2488,32 +2414,27 @@ function baseMove(state, orig, dest) {
2488
2414
  callUserFunction(state.events.change);
2489
2415
  return captured || true;
2490
2416
  }
2491
-
2492
- exports.baseMove = baseMove;
2493
-
2494
2417
  function baseNewPiece(state, piece, key, force) {
2495
- if (state.pieces[key]) {
2496
- if (force) delete state.pieces[key];else return false;
2418
+ if (state.pieces.has(key)) {
2419
+ if (force) state.pieces.delete(key);else return false;
2497
2420
  }
2498
2421
 
2499
2422
  callUserFunction(state.events.dropNewPiece, piece, key);
2500
- state.pieces[key] = piece;
2423
+ state.pieces.set(key, piece);
2501
2424
  state.lastMove = [key];
2502
2425
  state.check = undefined;
2503
2426
  callUserFunction(state.events.change);
2504
2427
  state.movable.dests = undefined;
2505
- state.turnColor = util.opposite(state.turnColor);
2428
+ state.turnColor = opposite(state.turnColor);
2506
2429
  return true;
2507
2430
  }
2508
2431
 
2509
- exports.baseNewPiece = baseNewPiece;
2510
-
2511
2432
  function baseUserMove(state, orig, dest) {
2512
2433
  const result = baseMove(state, orig, dest);
2513
2434
 
2514
2435
  if (result) {
2515
2436
  state.movable.dests = undefined;
2516
- state.turnColor = util.opposite(state.turnColor);
2437
+ state.turnColor = opposite(state.turnColor);
2517
2438
  state.animation.current = undefined;
2518
2439
  }
2519
2440
 
@@ -2547,30 +2468,26 @@ function userMove(state, orig, dest) {
2547
2468
  unselect(state);
2548
2469
  return false;
2549
2470
  }
2550
-
2551
- exports.userMove = userMove;
2552
-
2553
2471
  function dropNewPiece(state, orig, dest, force) {
2554
- if (canDrop(state, orig, dest) || force) {
2555
- const piece = state.pieces[orig];
2556
- delete state.pieces[orig];
2472
+ const piece = state.pieces.get(orig);
2473
+
2474
+ if (piece && (canDrop(state, orig, dest) || force)) {
2475
+ state.pieces.delete(orig);
2557
2476
  baseNewPiece(state, piece, dest, force);
2558
2477
  callUserFunction(state.movable.events.afterNewPiece, piece.role, dest, {
2478
+ premove: false,
2559
2479
  predrop: false
2560
2480
  });
2561
- } else if (canPredrop(state, orig, dest)) {
2562
- setPredrop(state, state.pieces[orig].role, dest);
2481
+ } else if (piece && canPredrop(state, orig, dest)) {
2482
+ setPredrop(state, piece.role, dest);
2563
2483
  } else {
2564
2484
  unsetPremove(state);
2565
2485
  unsetPredrop(state);
2566
2486
  }
2567
2487
 
2568
- delete state.pieces[orig];
2488
+ state.pieces.delete(orig);
2569
2489
  unselect(state);
2570
2490
  }
2571
-
2572
- exports.dropNewPiece = dropNewPiece;
2573
-
2574
2491
  function selectSquare(state, key, force) {
2575
2492
  callUserFunction(state.events.select, key);
2576
2493
 
@@ -2592,65 +2509,54 @@ function selectSquare(state, key, force) {
2592
2509
  state.hold.start();
2593
2510
  }
2594
2511
  }
2595
-
2596
- exports.selectSquare = selectSquare;
2597
-
2598
2512
  function setSelected(state, key) {
2599
2513
  state.selected = key;
2600
2514
 
2601
2515
  if (isPremovable(state, key)) {
2602
- state.premovable.dests = premove_1.default(state.pieces, key, state.premovable.castle);
2516
+ state.premovable.dests = premove(state.pieces, key, state.premovable.castle);
2603
2517
  } else state.premovable.dests = undefined;
2604
2518
  }
2605
-
2606
- exports.setSelected = setSelected;
2607
-
2608
2519
  function unselect(state) {
2609
2520
  state.selected = undefined;
2610
2521
  state.premovable.dests = undefined;
2611
2522
  state.hold.cancel();
2612
2523
  }
2613
2524
 
2614
- exports.unselect = unselect;
2615
-
2616
2525
  function isMovable(state, orig) {
2617
- const piece = state.pieces[orig];
2526
+ const piece = state.pieces.get(orig);
2618
2527
  return !!piece && (state.movable.color === 'both' || state.movable.color === piece.color && state.turnColor === piece.color);
2619
2528
  }
2620
2529
 
2621
2530
  function canMove(state, orig, dest) {
2622
- return orig !== dest && isMovable(state, orig) && (state.movable.free || !!state.movable.dests && util.containsX(state.movable.dests[orig], dest));
2623
- }
2531
+ var _a, _b;
2624
2532
 
2625
- exports.canMove = canMove;
2533
+ 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)));
2534
+ }
2626
2535
 
2627
2536
  function canDrop(state, orig, dest) {
2628
- const piece = state.pieces[orig];
2629
- return !!piece && dest && (orig === dest || !state.pieces[dest]) && (state.movable.color === 'both' || state.movable.color === piece.color && state.turnColor === piece.color);
2537
+ const piece = state.pieces.get(orig);
2538
+ return !!piece && (orig === dest || !state.pieces.has(dest)) && (state.movable.color === 'both' || state.movable.color === piece.color && state.turnColor === piece.color);
2630
2539
  }
2631
2540
 
2632
2541
  function isPremovable(state, orig) {
2633
- const piece = state.pieces[orig];
2542
+ const piece = state.pieces.get(orig);
2634
2543
  return !!piece && state.premovable.enabled && state.movable.color === piece.color && state.turnColor !== piece.color;
2635
2544
  }
2636
2545
 
2637
2546
  function canPremove(state, orig, dest) {
2638
- return orig !== dest && isPremovable(state, orig) && util.containsX(premove_1.default(state.pieces, orig, state.premovable.castle), dest);
2547
+ return orig !== dest && isPremovable(state, orig) && premove(state.pieces, orig, state.premovable.castle).includes(dest);
2639
2548
  }
2640
2549
 
2641
2550
  function canPredrop(state, orig, dest) {
2642
- const piece = state.pieces[orig];
2643
- const destPiece = state.pieces[dest];
2644
- return !!piece && dest && (!destPiece || destPiece.color !== state.movable.color) && state.predroppable.enabled && (piece.role !== 'pawn' || dest[1] !== '1' && dest[1] !== '8') && state.movable.color === piece.color && state.turnColor !== piece.color;
2551
+ const piece = state.pieces.get(orig);
2552
+ const destPiece = state.pieces.get(dest);
2553
+ return !!piece && (!destPiece || destPiece.color !== state.movable.color) && state.predroppable.enabled && (piece.role !== 'pawn' || dest[1] !== '1' && dest[1] !== '8') && state.movable.color === piece.color && state.turnColor !== piece.color;
2645
2554
  }
2646
2555
 
2647
2556
  function isDraggable(state, orig) {
2648
- const piece = state.pieces[orig];
2557
+ const piece = state.pieces.get(orig);
2649
2558
  return !!piece && state.draggable.enabled && (state.movable.color === 'both' || state.movable.color === piece.color && (state.turnColor === piece.color || state.premovable.enabled));
2650
2559
  }
2651
-
2652
- exports.isDraggable = isDraggable;
2653
-
2654
2560
  function playPremove(state) {
2655
2561
  const move = state.premovable.current;
2656
2562
  if (!move) return false;
@@ -2674,9 +2580,6 @@ function playPremove(state) {
2674
2580
  unsetPremove(state);
2675
2581
  return success;
2676
2582
  }
2677
-
2678
- exports.playPremove = playPremove;
2679
-
2680
2583
  function playPredrop(state, validate) {
2681
2584
  const drop = state.predroppable.current;
2682
2585
  let success = false;
@@ -2690,6 +2593,7 @@ function playPredrop(state, validate) {
2690
2593
 
2691
2594
  if (baseNewPiece(state, piece, drop.key)) {
2692
2595
  callUserFunction(state.movable.events.afterNewPiece, drop.role, drop.key, {
2596
+ premove: false,
2693
2597
  predrop: true
2694
2598
  });
2695
2599
  success = true;
@@ -2699,52 +2603,37 @@ function playPredrop(state, validate) {
2699
2603
  unsetPredrop(state);
2700
2604
  return success;
2701
2605
  }
2702
-
2703
- exports.playPredrop = playPredrop;
2704
-
2705
2606
  function cancelMove(state) {
2706
2607
  unsetPremove(state);
2707
2608
  unsetPredrop(state);
2708
2609
  unselect(state);
2709
2610
  }
2710
-
2711
- exports.cancelMove = cancelMove;
2712
-
2713
2611
  function stop(state) {
2714
2612
  state.movable.color = state.movable.dests = state.animation.current = undefined;
2715
2613
  cancelMove(state);
2716
2614
  }
2717
-
2718
- exports.stop = stop;
2719
-
2720
2615
  function getKeyAtDomPos(pos, asWhite, bounds) {
2721
- let file = Math.ceil(8 * ((pos[0] - bounds.left) / bounds.width));
2722
- if (!asWhite) file = 9 - file;
2723
- let rank = Math.ceil(8 - 8 * ((pos[1] - bounds.top) / bounds.height));
2724
- if (!asWhite) rank = 9 - rank;
2725
- return file > 0 && file < 9 && rank > 0 && rank < 9 ? util.pos2key([file, rank]) : undefined;
2616
+ let file = Math.floor(8 * (pos[0] - bounds.left) / bounds.width);
2617
+ if (!asWhite) file = 7 - file;
2618
+ let rank = 7 - Math.floor(8 * (pos[1] - bounds.top) / bounds.height);
2619
+ if (!asWhite) rank = 7 - rank;
2620
+ return file >= 0 && file < 8 && rank >= 0 && rank < 8 ? pos2key([file, rank]) : undefined;
2621
+ }
2622
+ function getSnappedKeyAtDomPos(orig, pos, asWhite, bounds) {
2623
+ const origPos = key2pos(orig);
2624
+ const validSnapPos = allPos.filter(pos2 => {
2625
+ return queen(origPos[0], origPos[1], pos2[0], pos2[1]) || knight(origPos[0], origPos[1], pos2[0], pos2[1]);
2626
+ });
2627
+ const validSnapCenters = validSnapPos.map(pos2 => computeSquareCenter(pos2key(pos2), asWhite, bounds));
2628
+ const validSnapDistances = validSnapCenters.map(pos2 => distanceSq(pos, pos2));
2629
+ const [, closestSnapIndex] = validSnapDistances.reduce((a, b, index) => a[0] < b ? a : [b, index], [validSnapDistances[0], 0]);
2630
+ return pos2key(validSnapPos[closestSnapIndex]);
2726
2631
  }
2727
-
2728
- exports.getKeyAtDomPos = getKeyAtDomPos;
2729
-
2730
2632
  function whitePov(s) {
2731
2633
  return s.orientation === 'white';
2732
2634
  }
2733
2635
 
2734
- exports.whitePov = whitePov;
2735
- });
2736
-
2737
- var fen = createCommonjsModule(function (module, exports) {
2738
-
2739
- Object.defineProperty(exports, "__esModule", {
2740
- value: true
2741
- });
2742
-
2743
-
2744
-
2745
-
2746
-
2747
- exports.initial = 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR';
2636
+ const initial = 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR';
2748
2637
  const roles = {
2749
2638
  p: 'pawn',
2750
2639
  r: 'rook',
@@ -2761,11 +2650,10 @@ const letters = {
2761
2650
  queen: 'q',
2762
2651
  king: 'k'
2763
2652
  };
2764
-
2765
2653
  function read(fen) {
2766
- if (fen === 'start') fen = exports.initial;
2767
- const pieces = {};
2768
- let row = 8,
2654
+ if (fen === 'start') fen = initial;
2655
+ const pieces = new Map();
2656
+ let row = 7,
2769
2657
  col = 0;
2770
2658
 
2771
2659
  for (const c of fen) {
@@ -2775,36 +2663,37 @@ function read(fen) {
2775
2663
 
2776
2664
  case '/':
2777
2665
  --row;
2778
- if (row === 0) return pieces;
2666
+ if (row < 0) return pieces;
2779
2667
  col = 0;
2780
2668
  break;
2781
2669
 
2782
2670
  case '~':
2783
- const piece = pieces[util.pos2key([col, row])];
2784
- if (piece) piece.promoted = true;
2785
- break;
2671
+ {
2672
+ const piece = pieces.get(pos2key([col, row]));
2673
+ if (piece) piece.promoted = true;
2674
+ break;
2675
+ }
2786
2676
 
2787
2677
  default:
2788
- const nb = c.charCodeAt(0);
2789
- if (nb < 57) col += nb - 48;else {
2790
- ++col;
2791
- const role = c.toLowerCase();
2792
- pieces[util.pos2key([col, row])] = {
2793
- role: roles[role],
2794
- color: c === role ? 'black' : 'white'
2795
- };
2678
+ {
2679
+ const nb = c.charCodeAt(0);
2680
+ if (nb < 57) col += nb - 48;else {
2681
+ const role = c.toLowerCase();
2682
+ pieces.set(pos2key([col, row]), {
2683
+ role: roles[role],
2684
+ color: c === role ? 'black' : 'white'
2685
+ });
2686
+ ++col;
2687
+ }
2796
2688
  }
2797
2689
  }
2798
2690
  }
2799
2691
 
2800
2692
  return pieces;
2801
2693
  }
2802
-
2803
- exports.read = read;
2804
-
2805
2694
  function write(pieces) {
2806
- return util.invRanks.map(y => types.ranks.map(x => {
2807
- const piece = pieces[util.pos2key([x, y])];
2695
+ return invRanks.map(y => files.map(x => {
2696
+ const piece = pieces.get(x + y);
2808
2697
 
2809
2698
  if (piece) {
2810
2699
  const letter = letters[piece.role];
@@ -2813,112 +2702,99 @@ function write(pieces) {
2813
2702
  }).join('')).join('/').replace(/1{2,}/g, s => s.length.toString());
2814
2703
  }
2815
2704
 
2816
- exports.write = write;
2817
- });
2818
-
2819
- var config = createCommonjsModule(function (module, exports) {
2820
-
2821
- Object.defineProperty(exports, "__esModule", {
2822
- value: true
2823
- });
2824
-
2825
-
2705
+ function applyAnimation(state, config) {
2706
+ if (config.animation) {
2707
+ deepMerge(state.animation, config.animation); // no need for such short animations
2826
2708
 
2709
+ if ((state.animation.duration || 0) < 70) state.animation.enabled = false;
2710
+ }
2711
+ }
2712
+ function configure(state, config) {
2713
+ var _a, _b; // don't merge destinations and autoShapes. Just override.
2827
2714
 
2828
2715
 
2829
- function configure(state, config) {
2830
- if (config.movable && config.movable.dests) state.movable.dests = undefined;
2831
- merge(state, config);
2716
+ if ((_a = config.movable) === null || _a === void 0 ? void 0 : _a.dests) state.movable.dests = undefined;
2717
+ if ((_b = config.drawable) === null || _b === void 0 ? void 0 : _b.autoShapes) state.drawable.autoShapes = [];
2718
+ deepMerge(state, config); // if a fen was provided, replace the pieces
2832
2719
 
2833
2720
  if (config.fen) {
2834
- state.pieces = fen.read(config.fen);
2721
+ state.pieces = read(config.fen);
2835
2722
  state.drawable.shapes = [];
2836
- }
2723
+ } // apply config values that could be undefined yet meaningful
2724
+
2837
2725
 
2838
- if (config.hasOwnProperty('check')) board.setCheck(state, config.check || false);
2839
- if (config.hasOwnProperty('lastMove') && !config.lastMove) state.lastMove = undefined;else if (config.lastMove) state.lastMove = config.lastMove;
2840
- if (state.selected) board.setSelected(state, state.selected);
2841
- if (!state.animation.duration || state.animation.duration < 100) state.animation.enabled = false;
2726
+ if ('check' in config) setCheck(state, config.check || false);
2727
+ if ('lastMove' in config && !config.lastMove) state.lastMove = undefined; // in case of ZH drop last move, there's a single square.
2728
+ // if the previous last move had two squares,
2729
+ // the merge algorithm will incorrectly keep the second square.
2730
+ else if (config.lastMove) state.lastMove = config.lastMove; // fix move/premove dests
2731
+
2732
+ if (state.selected) setSelected(state, state.selected);
2733
+ applyAnimation(state, config);
2842
2734
 
2843
2735
  if (!state.movable.rookCastle && state.movable.dests) {
2844
- const rank = state.movable.color === 'white' ? 1 : 8,
2736
+ const rank = state.movable.color === 'white' ? '1' : '8',
2845
2737
  kingStartPos = 'e' + rank,
2846
- dests = state.movable.dests[kingStartPos],
2847
- king = state.pieces[kingStartPos];
2738
+ dests = state.movable.dests.get(kingStartPos),
2739
+ king = state.pieces.get(kingStartPos);
2848
2740
  if (!dests || !king || king.role !== 'king') return;
2849
- state.movable.dests[kingStartPos] = dests.filter(d => !(d === 'a' + rank && dests.indexOf('c' + rank) !== -1) && !(d === 'h' + rank && dests.indexOf('g' + rank) !== -1));
2741
+ state.movable.dests.set(kingStartPos, dests.filter(d => !(d === 'a' + rank && dests.includes('c' + rank)) && !(d === 'h' + rank && dests.includes('g' + rank))));
2850
2742
  }
2851
2743
  }
2852
2744
 
2853
- exports.configure = configure;
2854
-
2855
- function merge(base, extend) {
2745
+ function deepMerge(base, extend) {
2856
2746
  for (const key in extend) {
2857
- if (isObject(base[key]) && isObject(extend[key])) merge(base[key], extend[key]);else base[key] = extend[key];
2747
+ if (isObject(base[key]) && isObject(extend[key])) deepMerge(base[key], extend[key]);else base[key] = extend[key];
2858
2748
  }
2859
2749
  }
2860
2750
 
2861
2751
  function isObject(o) {
2862
2752
  return typeof o === 'object';
2863
2753
  }
2864
- });
2865
-
2866
- var anim_1 = createCommonjsModule(function (module, exports) {
2867
-
2868
- Object.defineProperty(exports, "__esModule", {
2869
- value: true
2870
- });
2871
-
2872
-
2873
2754
 
2874
2755
  function anim(mutation, state) {
2875
2756
  return state.animation.enabled ? animate(mutation, state) : render(mutation, state);
2876
2757
  }
2877
-
2878
- exports.anim = anim;
2879
-
2880
2758
  function render(mutation, state) {
2881
2759
  const result = mutation(state);
2882
2760
  state.dom.redraw();
2883
2761
  return result;
2884
2762
  }
2885
2763
 
2886
- exports.render = render;
2887
-
2888
2764
  function makePiece(key, piece) {
2889
2765
  return {
2890
2766
  key: key,
2891
- pos: util.key2pos(key),
2767
+ pos: key2pos(key),
2892
2768
  piece: piece
2893
2769
  };
2894
2770
  }
2895
2771
 
2896
2772
  function closer(piece, pieces) {
2897
2773
  return pieces.sort((p1, p2) => {
2898
- return util.distanceSq(piece.pos, p1.pos) - util.distanceSq(piece.pos, p2.pos);
2774
+ return distanceSq(piece.pos, p1.pos) - distanceSq(piece.pos, p2.pos);
2899
2775
  })[0];
2900
2776
  }
2901
2777
 
2902
2778
  function computePlan(prevPieces, current) {
2903
- const anims = {},
2779
+ const anims = new Map(),
2904
2780
  animedOrigs = [],
2905
- fadings = {},
2781
+ fadings = new Map(),
2906
2782
  missings = [],
2907
2783
  news = [],
2908
- prePieces = {};
2784
+ prePieces = new Map();
2909
2785
  let curP, preP, vector;
2910
2786
 
2911
- for (const i in prevPieces) {
2912
- prePieces[i] = makePiece(i, prevPieces[i]);
2787
+ for (const [k, p] of prevPieces) {
2788
+ prePieces.set(k, makePiece(k, p));
2913
2789
  }
2914
2790
 
2915
- for (const key of util.allKeys) {
2916
- curP = current.pieces[key];
2917
- preP = prePieces[key];
2791
+ for (const key of allKeys) {
2792
+ curP = current.pieces.get(key);
2793
+ preP = prePieces.get(key);
2918
2794
 
2919
2795
  if (curP) {
2920
2796
  if (preP) {
2921
- if (!util.samePiece(curP, preP.piece)) {
2797
+ if (!samePiece(curP, preP.piece)) {
2922
2798
  missings.push(preP);
2923
2799
  news.push(makePiece(key, curP));
2924
2800
  }
@@ -2927,17 +2803,17 @@ function computePlan(prevPieces, current) {
2927
2803
  }
2928
2804
 
2929
2805
  for (const newP of news) {
2930
- preP = closer(newP, missings.filter(p => util.samePiece(newP.piece, p.piece)));
2806
+ preP = closer(newP, missings.filter(p => samePiece(newP.piece, p.piece)));
2931
2807
 
2932
2808
  if (preP) {
2933
2809
  vector = [preP.pos[0] - newP.pos[0], preP.pos[1] - newP.pos[1]];
2934
- anims[newP.key] = vector.concat(vector);
2810
+ anims.set(newP.key, vector.concat(vector));
2935
2811
  animedOrigs.push(preP.key);
2936
2812
  }
2937
2813
  }
2938
2814
 
2939
2815
  for (const p of missings) {
2940
- if (!util.containsX(animedOrigs, p.key)) fadings[p.key] = p.piece;
2816
+ if (!animedOrigs.includes(p.key)) fadings.set(p.key, p.piece);
2941
2817
  }
2942
2818
 
2943
2819
  return {
@@ -2950,6 +2826,7 @@ function step(state, now) {
2950
2826
  const cur = state.animation.current;
2951
2827
 
2952
2828
  if (cur === undefined) {
2829
+ // animation was canceled :(
2953
2830
  if (!state.dom.destroyed) state.dom.redrawNow();
2954
2831
  return;
2955
2832
  }
@@ -2962,23 +2839,24 @@ function step(state, now) {
2962
2839
  } else {
2963
2840
  const ease = easing(rest);
2964
2841
 
2965
- for (const i in cur.plan.anims) {
2966
- const cfg = cur.plan.anims[i];
2842
+ for (const cfg of cur.plan.anims.values()) {
2967
2843
  cfg[2] = cfg[0] * ease;
2968
2844
  cfg[3] = cfg[1] * ease;
2969
2845
  }
2970
2846
 
2971
- state.dom.redrawNow(true);
2847
+ state.dom.redrawNow(true); // optimisation: don't render SVG changes during animations
2848
+
2972
2849
  requestAnimationFrame((now = performance.now()) => step(state, now));
2973
2850
  }
2974
2851
  }
2975
2852
 
2976
2853
  function animate(mutation, state) {
2977
- const prevPieces = Object.assign({}, state.pieces);
2854
+ // clone state before mutating it
2855
+ const prevPieces = new Map(state.pieces);
2978
2856
  const result = mutation(state);
2979
2857
  const plan = computePlan(prevPieces, state);
2980
2858
 
2981
- if (!isObjectEmpty(plan.anims) || !isObjectEmpty(plan.fadings)) {
2859
+ if (plan.anims.size || plan.fadings.size) {
2982
2860
  const alreadyRunning = state.animation.current && state.animation.current.start;
2983
2861
  state.animation.current = {
2984
2862
  start: performance.now(),
@@ -2987,59 +2865,48 @@ function animate(mutation, state) {
2987
2865
  };
2988
2866
  if (!alreadyRunning) step(state, performance.now());
2989
2867
  } else {
2868
+ // don't animate, just render right away
2990
2869
  state.dom.redraw();
2991
2870
  }
2992
2871
 
2993
2872
  return result;
2994
- }
2873
+ } // https://gist.github.com/gre/1650294
2995
2874
 
2996
- function isObjectEmpty(o) {
2997
- for (const _ in o) return false;
2998
-
2999
- return true;
3000
- }
3001
2875
 
3002
2876
  function easing(t) {
3003
2877
  return t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1;
3004
2878
  }
3005
- });
3006
-
3007
- var draw = createCommonjsModule(function (module, exports) {
3008
-
3009
- Object.defineProperty(exports, "__esModule", {
3010
- value: true
3011
- });
3012
-
3013
-
3014
-
3015
-
3016
2879
 
3017
2880
  const brushes = ['green', 'red', 'blue', 'yellow'];
3018
-
3019
2881
  function start(state, e) {
2882
+ // support one finger touch only
3020
2883
  if (e.touches && e.touches.length > 1) return;
3021
2884
  e.stopPropagation();
3022
2885
  e.preventDefault();
3023
- e.ctrlKey ? board.unselect(state) : board.cancelMove(state);
3024
- const pos = util.eventPosition(e),
3025
- orig = board.getKeyAtDomPos(pos, board.whitePov(state), state.dom.bounds());
2886
+ e.ctrlKey ? unselect(state) : cancelMove(state);
2887
+ const pos = eventPosition(e),
2888
+ orig = getKeyAtDomPos(pos, whitePov(state), state.dom.bounds());
3026
2889
  if (!orig) return;
3027
2890
  state.drawable.current = {
3028
2891
  orig,
3029
2892
  pos,
3030
- brush: eventBrush(e)
2893
+ brush: eventBrush(e),
2894
+ snapToValidMove: state.drawable.defaultSnapToValidMove
3031
2895
  };
3032
2896
  processDraw(state);
3033
2897
  }
3034
-
3035
- exports.start = start;
3036
-
3037
2898
  function processDraw(state) {
3038
2899
  requestAnimationFrame(() => {
3039
2900
  const cur = state.drawable.current;
3040
2901
 
3041
2902
  if (cur) {
3042
- const mouseSq = board.getKeyAtDomPos(cur.pos, board.whitePov(state), state.dom.bounds());
2903
+ const keyAtDomPos = getKeyAtDomPos(cur.pos, whitePov(state), state.dom.bounds());
2904
+
2905
+ if (!keyAtDomPos) {
2906
+ cur.snapToValidMove = false;
2907
+ }
2908
+
2909
+ const mouseSq = cur.snapToValidMove ? getSnappedKeyAtDomPos(cur.orig, cur.pos, whitePov(state), state.dom.bounds()) : keyAtDomPos;
3043
2910
 
3044
2911
  if (mouseSq !== cur.mouseSq) {
3045
2912
  cur.mouseSq = mouseSq;
@@ -3051,15 +2918,9 @@ function processDraw(state) {
3051
2918
  }
3052
2919
  });
3053
2920
  }
3054
-
3055
- exports.processDraw = processDraw;
3056
-
3057
2921
  function move(state, e) {
3058
- if (state.drawable.current) state.drawable.current.pos = util.eventPosition(e);
2922
+ if (state.drawable.current) state.drawable.current.pos = eventPosition(e);
3059
2923
  }
3060
-
3061
- exports.move = move;
3062
-
3063
2924
  function end(state) {
3064
2925
  const cur = state.drawable.current;
3065
2926
 
@@ -3068,18 +2929,12 @@ function end(state) {
3068
2929
  cancel(state);
3069
2930
  }
3070
2931
  }
3071
-
3072
- exports.end = end;
3073
-
3074
2932
  function cancel(state) {
3075
2933
  if (state.drawable.current) {
3076
2934
  state.drawable.current = undefined;
3077
2935
  state.dom.redraw();
3078
2936
  }
3079
2937
  }
3080
-
3081
- exports.cancel = cancel;
3082
-
3083
2938
  function clear(state) {
3084
2939
  if (state.drawable.shapes.length) {
3085
2940
  state.drawable.shapes = [];
@@ -3088,11 +2943,11 @@ function clear(state) {
3088
2943
  }
3089
2944
  }
3090
2945
 
3091
- exports.clear = clear;
3092
-
3093
2946
  function eventBrush(e) {
3094
- const modA = (e.shiftKey || e.ctrlKey) && util.isRightButton(e);
3095
- const modB = e.altKey || e.metaKey || e.getModifierState('AltGraph');
2947
+ var _a;
2948
+
2949
+ const modA = (e.shiftKey || e.ctrlKey) && isRightButton(e);
2950
+ const modB = e.altKey || e.metaKey || ((_a = e.getModifierState) === null || _a === void 0 ? void 0 : _a.call(e, 'AltGraph'));
3096
2951
  return brushes[(modA ? 1 : 0) + (modB ? 2 : 0)];
3097
2952
  }
3098
2953
 
@@ -3108,136 +2963,115 @@ function addShape(drawable, cur) {
3108
2963
  function onChange(drawable) {
3109
2964
  if (drawable.onChange) drawable.onChange(drawable.shapes);
3110
2965
  }
3111
- });
3112
-
3113
- var drag = createCommonjsModule(function (module, exports) {
3114
-
3115
- Object.defineProperty(exports, "__esModule", {
3116
- value: true
3117
- });
3118
2966
 
2967
+ function start$1(s, e) {
2968
+ if (!e.isTrusted || e.button !== undefined && e.button !== 0) return; // only touch or left click
3119
2969
 
2970
+ if (e.touches && e.touches.length > 1) return; // support one finger touch only
3120
2971
 
3121
-
3122
-
3123
-
3124
-
3125
-
3126
-
3127
- function start(s, e) {
3128
- if (e.button !== undefined && e.button !== 0) return;
3129
- if (e.touches && e.touches.length > 1) return;
3130
2972
  const bounds = s.dom.bounds(),
3131
- position = util.eventPosition(e),
3132
- orig = board.getKeyAtDomPos(position, board.whitePov(s), bounds);
2973
+ position = eventPosition(e),
2974
+ orig = getKeyAtDomPos(position, whitePov(s), bounds);
3133
2975
  if (!orig) return;
3134
- const piece = s.pieces[orig];
2976
+ const piece = s.pieces.get(orig);
3135
2977
  const previouslySelected = s.selected;
3136
- if (!previouslySelected && s.drawable.enabled && (s.drawable.eraseOnClick || !piece || piece.color !== s.turnColor)) draw.clear(s);
3137
- if (e.cancelable !== false && (!e.touches || !s.movable.color || piece || previouslySelected || pieceCloseTo(s, position))) e.preventDefault();
2978
+ if (!previouslySelected && s.drawable.enabled && (s.drawable.eraseOnClick || !piece || piece.color !== s.turnColor)) clear(s); // Prevent touch scroll and create no corresponding mouse event, if there
2979
+ // is an intent to interact with the board.
2980
+
2981
+ if (e.cancelable !== false && (!e.touches || s.blockTouchScroll || piece || previouslySelected || pieceCloseTo(s, position))) e.preventDefault();
3138
2982
  const hadPremove = !!s.premovable.current;
3139
2983
  const hadPredrop = !!s.predroppable.current;
3140
2984
  s.stats.ctrlKey = e.ctrlKey;
3141
2985
 
3142
- if (s.selected && board.canMove(s, s.selected, orig)) {
3143
- anim_1.anim(state => board.selectSquare(state, orig), s);
2986
+ if (s.selected && canMove(s, s.selected, orig)) {
2987
+ anim(state => selectSquare(state, orig), s);
3144
2988
  } else {
3145
- board.selectSquare(s, orig);
2989
+ selectSquare(s, orig);
3146
2990
  }
3147
2991
 
3148
2992
  const stillSelected = s.selected === orig;
3149
2993
  const element = pieceElementByKey(s, orig);
3150
2994
 
3151
- if (piece && element && stillSelected && board.isDraggable(s, orig)) {
3152
- const squareBounds = computeSquareBounds(orig, board.whitePov(s), bounds);
2995
+ if (piece && element && stillSelected && isDraggable(s, orig)) {
3153
2996
  s.draggable.current = {
3154
2997
  orig,
3155
- origPos: util.key2pos(orig),
3156
2998
  piece,
3157
- rel: position,
3158
- epos: position,
3159
- pos: [0, 0],
3160
- dec: s.draggable.centerPiece ? [position[0] - (squareBounds.left + squareBounds.width / 2), position[1] - (squareBounds.top + squareBounds.height / 2)] : [0, 0],
2999
+ origPos: position,
3000
+ pos: position,
3161
3001
  started: s.draggable.autoDistance && s.stats.dragged,
3162
3002
  element,
3163
3003
  previouslySelected,
3164
- originTarget: e.target
3004
+ originTarget: e.target,
3005
+ keyHasChanged: false
3165
3006
  };
3166
3007
  element.cgDragging = true;
3167
- element.classList.add('dragging');
3008
+ element.classList.add('dragging'); // place ghost
3009
+
3168
3010
  const ghost = s.dom.elements.ghost;
3169
3011
 
3170
3012
  if (ghost) {
3171
3013
  ghost.className = `ghost ${piece.color} ${piece.role}`;
3172
- util.translateAbs(ghost, util.posToTranslateAbs(bounds)(util.key2pos(orig), board.whitePov(s)));
3173
- util.setVisible(ghost, true);
3014
+ translate(ghost, posToTranslate(bounds)(key2pos(orig), whitePov(s)));
3015
+ setVisible(ghost, true);
3174
3016
  }
3175
3017
 
3176
3018
  processDrag(s);
3177
3019
  } else {
3178
- if (hadPremove) board.unsetPremove(s);
3179
- if (hadPredrop) board.unsetPredrop(s);
3020
+ if (hadPremove) unsetPremove(s);
3021
+ if (hadPredrop) unsetPredrop(s);
3180
3022
  }
3181
3023
 
3182
3024
  s.dom.redraw();
3183
3025
  }
3184
3026
 
3185
- exports.start = start;
3186
-
3187
3027
  function pieceCloseTo(s, pos) {
3188
- const asWhite = board.whitePov(s),
3028
+ const asWhite = whitePov(s),
3189
3029
  bounds = s.dom.bounds(),
3190
3030
  radiusSq = Math.pow(bounds.width / 8, 2);
3191
3031
 
3192
- for (const key in s.pieces) {
3193
- const squareBounds = computeSquareBounds(key, asWhite, bounds),
3194
- center = [squareBounds.left + squareBounds.width / 2, squareBounds.top + squareBounds.height / 2];
3195
- if (util.distanceSq(center, pos) <= radiusSq) return true;
3032
+ for (const key of s.pieces.keys()) {
3033
+ const center = computeSquareCenter(key, asWhite, bounds);
3034
+ if (distanceSq(center, pos) <= radiusSq) return true;
3196
3035
  }
3197
3036
 
3198
3037
  return false;
3199
3038
  }
3200
3039
 
3201
- exports.pieceCloseTo = pieceCloseTo;
3202
-
3203
3040
  function dragNewPiece(s, piece, e, force) {
3204
3041
  const key = 'a0';
3205
- s.pieces[key] = piece;
3042
+ s.pieces.set(key, piece);
3206
3043
  s.dom.redraw();
3207
- const position = util.eventPosition(e),
3208
- asWhite = board.whitePov(s),
3209
- bounds = s.dom.bounds(),
3210
- squareBounds = computeSquareBounds(key, asWhite, bounds);
3211
- const rel = [(asWhite ? 0 : 7) * squareBounds.width + bounds.left, (asWhite ? 8 : -1) * squareBounds.height + bounds.top];
3044
+ const position = eventPosition(e);
3212
3045
  s.draggable.current = {
3213
3046
  orig: key,
3214
- origPos: util.key2pos(key),
3215
3047
  piece,
3216
- rel,
3217
- epos: position,
3218
- pos: [position[0] - rel[0], position[1] - rel[1]],
3219
- dec: [-squareBounds.width / 2, -squareBounds.height / 2],
3048
+ origPos: position,
3049
+ pos: position,
3220
3050
  started: true,
3221
3051
  element: () => pieceElementByKey(s, key),
3222
3052
  originTarget: e.target,
3223
3053
  newPiece: true,
3224
- force: !!force
3054
+ force: !!force,
3055
+ keyHasChanged: false
3225
3056
  };
3226
3057
  processDrag(s);
3227
3058
  }
3228
3059
 
3229
- exports.dragNewPiece = dragNewPiece;
3230
-
3231
3060
  function processDrag(s) {
3232
3061
  requestAnimationFrame(() => {
3062
+ var _a;
3063
+
3233
3064
  const cur = s.draggable.current;
3234
- if (!cur) return;
3235
- if (s.animation.current && s.animation.current.plan.anims[cur.orig]) s.animation.current = undefined;
3236
- const origPiece = s.pieces[cur.orig];
3237
- if (!origPiece || !util.samePiece(origPiece, cur.piece)) cancel(s);else {
3238
- if (!cur.started && util.distanceSq(cur.epos, cur.rel) >= Math.pow(s.draggable.distance, 2)) cur.started = true;
3065
+ if (!cur) return; // cancel animations while dragging
3066
+
3067
+ if ((_a = s.animation.current) === null || _a === void 0 ? void 0 : _a.plan.anims.has(cur.orig)) s.animation.current = undefined; // if moving piece is gone, cancel
3068
+
3069
+ const origPiece = s.pieces.get(cur.orig);
3070
+ if (!origPiece || !samePiece(origPiece, cur.piece)) cancel$1(s);else {
3071
+ if (!cur.started && distanceSq(cur.pos, cur.origPos) >= Math.pow(s.draggable.distance, 2)) cur.started = true;
3239
3072
 
3240
3073
  if (cur.started) {
3074
+ // support lazy elements
3241
3075
  if (typeof cur.element === 'function') {
3242
3076
  const found = cur.element();
3243
3077
  if (!found) return;
@@ -3246,93 +3080,71 @@ function processDrag(s) {
3246
3080
  cur.element = found;
3247
3081
  }
3248
3082
 
3249
- cur.pos = [cur.epos[0] - cur.rel[0], cur.epos[1] - cur.rel[1]];
3250
- const translation = util.posToTranslateAbs(s.dom.bounds())(cur.origPos, board.whitePov(s));
3251
- translation[0] += cur.pos[0] + cur.dec[0];
3252
- translation[1] += cur.pos[1] + cur.dec[1];
3253
- util.translateAbs(cur.element, translation);
3083
+ const bounds = s.dom.bounds();
3084
+ translate(cur.element, [cur.pos[0] - bounds.left - bounds.width / 16, cur.pos[1] - bounds.top - bounds.height / 16]);
3085
+ cur.keyHasChanged || (cur.keyHasChanged = cur.orig !== getKeyAtDomPos(cur.pos, whitePov(s), bounds));
3254
3086
  }
3255
3087
  }
3256
3088
  processDrag(s);
3257
3089
  });
3258
3090
  }
3259
3091
 
3260
- function move(s, e) {
3092
+ function move$1(s, e) {
3093
+ // support one finger touch only
3261
3094
  if (s.draggable.current && (!e.touches || e.touches.length < 2)) {
3262
- s.draggable.current.epos = util.eventPosition(e);
3095
+ s.draggable.current.pos = eventPosition(e);
3263
3096
  }
3264
3097
  }
3265
-
3266
- exports.move = move;
3267
-
3268
- function end(s, e) {
3098
+ function end$1(s, e) {
3269
3099
  const cur = s.draggable.current;
3270
- if (!cur) return;
3271
- if (e.type === 'touchend' && e.cancelable !== false) e.preventDefault();
3100
+ if (!cur) return; // create no corresponding mouse event
3272
3101
 
3273
- if (e.type === 'touchend' && cur && cur.originTarget !== e.target && !cur.newPiece) {
3102
+ if (e.type === 'touchend' && e.cancelable !== false) e.preventDefault(); // comparing with the origin target is an easy way to test that the end event
3103
+ // has the same touch origin
3104
+
3105
+ if (e.type === 'touchend' && cur.originTarget !== e.target && !cur.newPiece) {
3274
3106
  s.draggable.current = undefined;
3275
3107
  return;
3276
3108
  }
3277
3109
 
3278
- board.unsetPremove(s);
3279
- board.unsetPredrop(s);
3280
- const eventPos = util.eventPosition(e) || cur.epos;
3281
- const dest = board.getKeyAtDomPos(eventPos, board.whitePov(s), s.dom.bounds());
3110
+ unsetPremove(s);
3111
+ unsetPredrop(s); // touchend has no position; so use the last touchmove position instead
3112
+
3113
+ const eventPos = eventPosition(e) || cur.pos;
3114
+ const dest = getKeyAtDomPos(eventPos, whitePov(s), s.dom.bounds());
3282
3115
 
3283
3116
  if (dest && cur.started && cur.orig !== dest) {
3284
- if (cur.newPiece) board.dropNewPiece(s, cur.orig, dest, cur.force);else {
3117
+ if (cur.newPiece) dropNewPiece(s, cur.orig, dest, cur.force);else {
3285
3118
  s.stats.ctrlKey = e.ctrlKey;
3286
- if (board.userMove(s, cur.orig, dest)) s.stats.dragged = true;
3119
+ if (userMove(s, cur.orig, dest)) s.stats.dragged = true;
3287
3120
  }
3288
3121
  } else if (cur.newPiece) {
3289
- delete s.pieces[cur.orig];
3122
+ s.pieces.delete(cur.orig);
3290
3123
  } else if (s.draggable.deleteOnDropOff && !dest) {
3291
- delete s.pieces[cur.orig];
3292
- board.callUserFunction(s.events.change);
3124
+ s.pieces.delete(cur.orig);
3125
+ callUserFunction(s.events.change);
3293
3126
  }
3294
3127
 
3295
- if (cur.orig === cur.previouslySelected && (cur.orig === dest || !dest)) board.unselect(s);else if (!s.selectable.enabled) board.unselect(s);
3128
+ if ((cur.orig === cur.previouslySelected || cur.keyHasChanged) && (cur.orig === dest || !dest)) unselect(s);else if (!s.selectable.enabled) unselect(s);
3296
3129
  removeDragElements(s);
3297
3130
  s.draggable.current = undefined;
3298
3131
  s.dom.redraw();
3299
3132
  }
3300
-
3301
- exports.end = end;
3302
-
3303
- function cancel(s) {
3133
+ function cancel$1(s) {
3304
3134
  const cur = s.draggable.current;
3305
3135
 
3306
3136
  if (cur) {
3307
- if (cur.newPiece) delete s.pieces[cur.orig];
3137
+ if (cur.newPiece) s.pieces.delete(cur.orig);
3308
3138
  s.draggable.current = undefined;
3309
- board.unselect(s);
3139
+ unselect(s);
3310
3140
  removeDragElements(s);
3311
3141
  s.dom.redraw();
3312
3142
  }
3313
3143
  }
3314
3144
 
3315
- exports.cancel = cancel;
3316
-
3317
3145
  function removeDragElements(s) {
3318
3146
  const e = s.dom.elements;
3319
- if (e.ghost) util.setVisible(e.ghost, false);
3320
- }
3321
-
3322
- function computeSquareBounds(key, asWhite, bounds) {
3323
- const pos = util.key2pos(key);
3324
-
3325
- if (!asWhite) {
3326
- pos[0] = 9 - pos[0];
3327
- pos[1] = 9 - pos[1];
3328
- }
3329
-
3330
- return {
3331
- left: bounds.left + bounds.width * (pos[0] - 1) / 8,
3332
- top: bounds.top + bounds.height * (8 - pos[1]) / 8,
3333
- width: bounds.width / 8,
3334
- height: bounds.height / 8
3335
- };
3147
+ if (e.ghost) setVisible(e.ghost, false);
3336
3148
  }
3337
3149
 
3338
3150
  function pieceElementByKey(s, key) {
@@ -3343,15 +3155,8 @@ function pieceElementByKey(s, key) {
3343
3155
  el = el.nextSibling;
3344
3156
  }
3345
3157
 
3346
- return undefined;
3158
+ return;
3347
3159
  }
3348
- });
3349
-
3350
- var explosion_1 = createCommonjsModule(function (module, exports) {
3351
-
3352
- Object.defineProperty(exports, "__esModule", {
3353
- value: true
3354
- });
3355
3160
 
3356
3161
  function explosion(state, keys) {
3357
3162
  state.exploding = {
@@ -3365,71 +3170,53 @@ function explosion(state, keys) {
3365
3170
  }, 120);
3366
3171
  }
3367
3172
 
3368
- exports.default = explosion;
3369
-
3370
3173
  function setStage(state, stage) {
3371
3174
  if (state.exploding) {
3372
3175
  if (stage) state.exploding.stage = stage;else state.exploding = undefined;
3373
3176
  state.dom.redraw();
3374
3177
  }
3375
3178
  }
3376
- });
3377
-
3378
- var api = createCommonjsModule(function (module, exports) {
3379
-
3380
- Object.defineProperty(exports, "__esModule", {
3381
- value: true
3382
- });
3383
-
3384
-
3385
3179
 
3386
-
3387
-
3388
-
3389
-
3390
-
3391
-
3392
-
3393
-
3394
-
3395
-
3396
- function start(state, redrawAll) {
3397
- function toggleOrientation() {
3398
- board.toggleOrientation(state);
3180
+ function start$2(state, redrawAll) {
3181
+ function toggleOrientation$1() {
3182
+ toggleOrientation(state);
3399
3183
  redrawAll();
3400
3184
  }
3185
+
3401
3186
  return {
3402
- set(config$1) {
3403
- if (config$1.orientation && config$1.orientation !== state.orientation) toggleOrientation();
3404
- (config$1.fen ? anim_1.anim : anim_1.render)(state => config.configure(state, config$1), state);
3187
+ set(config) {
3188
+ if (config.orientation && config.orientation !== state.orientation) toggleOrientation$1();
3189
+ applyAnimation(state, config);
3190
+ (config.fen ? anim : render)(state => configure(state, config), state);
3405
3191
  },
3406
3192
 
3407
3193
  state,
3408
- getFen: () => fen.write(state.pieces),
3409
- toggleOrientation,
3194
+ getFen: () => write(state.pieces),
3195
+ toggleOrientation: toggleOrientation$1,
3410
3196
 
3411
3197
  setPieces(pieces) {
3412
- anim_1.anim(state => board.setPieces(state, pieces), state);
3198
+ anim(state => setPieces(state, pieces), state);
3413
3199
  },
3414
3200
 
3415
3201
  selectSquare(key, force) {
3416
- if (key) anim_1.anim(state => board.selectSquare(state, key, force), state);else if (state.selected) {
3417
- board.unselect(state);
3202
+ if (key) anim(state => selectSquare(state, key, force), state);else if (state.selected) {
3203
+ unselect(state);
3418
3204
  state.dom.redraw();
3419
3205
  }
3420
3206
  },
3421
3207
 
3422
3208
  move(orig, dest) {
3423
- anim_1.anim(state => board.baseMove(state, orig, dest), state);
3209
+ anim(state => baseMove(state, orig, dest), state);
3424
3210
  },
3425
3211
 
3426
3212
  newPiece(piece, key) {
3427
- anim_1.anim(state => board.baseNewPiece(state, piece, key), state);
3213
+ anim(state => baseNewPiece(state, piece, key), state);
3428
3214
  },
3429
3215
 
3430
3216
  playPremove() {
3431
3217
  if (state.premovable.current) {
3432
- if (anim_1.anim(board.playPremove, state)) return true;
3218
+ if (anim(playPremove, state)) return true; // if the premove couldn't be played, redraw to clear it up
3219
+
3433
3220
  state.dom.redraw();
3434
3221
  }
3435
3222
 
@@ -3438,7 +3225,7 @@ function start(state, redrawAll) {
3438
3225
 
3439
3226
  playPredrop(validate) {
3440
3227
  if (state.predroppable.current) {
3441
- const result = board.playPredrop(state, validate);
3228
+ const result = playPredrop(state, validate);
3442
3229
  state.dom.redraw();
3443
3230
  return result;
3444
3231
  }
@@ -3447,51 +3234,51 @@ function start(state, redrawAll) {
3447
3234
  },
3448
3235
 
3449
3236
  cancelPremove() {
3450
- anim_1.render(board.unsetPremove, state);
3237
+ render(unsetPremove, state);
3451
3238
  },
3452
3239
 
3453
3240
  cancelPredrop() {
3454
- anim_1.render(board.unsetPredrop, state);
3241
+ render(unsetPredrop, state);
3455
3242
  },
3456
3243
 
3457
3244
  cancelMove() {
3458
- anim_1.render(state => {
3459
- board.cancelMove(state);
3460
- drag.cancel(state);
3245
+ render(state => {
3246
+ cancelMove(state);
3247
+ cancel$1(state);
3461
3248
  }, state);
3462
3249
  },
3463
3250
 
3464
3251
  stop() {
3465
- anim_1.render(state => {
3466
- board.stop(state);
3467
- drag.cancel(state);
3252
+ render(state => {
3253
+ stop(state);
3254
+ cancel$1(state);
3468
3255
  }, state);
3469
3256
  },
3470
3257
 
3471
3258
  explode(keys) {
3472
- explosion_1.default(state, keys);
3259
+ explosion(state, keys);
3473
3260
  },
3474
3261
 
3475
3262
  setAutoShapes(shapes) {
3476
- anim_1.render(state => state.drawable.autoShapes = shapes, state);
3263
+ render(state => state.drawable.autoShapes = shapes, state);
3477
3264
  },
3478
3265
 
3479
3266
  setShapes(shapes) {
3480
- anim_1.render(state => state.drawable.shapes = shapes, state);
3267
+ render(state => state.drawable.shapes = shapes, state);
3481
3268
  },
3482
3269
 
3483
3270
  getKeyAtDomPos(pos) {
3484
- return board.getKeyAtDomPos(pos, board.whitePov(state), state.dom.bounds());
3271
+ return getKeyAtDomPos(pos, whitePov(state), state.dom.bounds());
3485
3272
  },
3486
3273
 
3487
3274
  redrawAll,
3488
3275
 
3489
3276
  dragNewPiece(piece, event, force) {
3490
- drag.dragNewPiece(state, piece, event, force);
3277
+ dragNewPiece(state, piece, event, force);
3491
3278
  },
3492
3279
 
3493
3280
  destroy() {
3494
- board.stop(state);
3281
+ stop(state);
3495
3282
  state.dom.unbind && state.dom.unbind();
3496
3283
  state.dom.destroyed = true;
3497
3284
  }
@@ -3499,30 +3286,18 @@ function start(state, redrawAll) {
3499
3286
  };
3500
3287
  }
3501
3288
 
3502
- exports.start = start;
3503
- });
3504
-
3505
- var state = createCommonjsModule(function (module, exports) {
3506
-
3507
- Object.defineProperty(exports, "__esModule", {
3508
- value: true
3509
- });
3510
-
3511
-
3512
-
3513
-
3514
-
3515
3289
  function defaults() {
3516
3290
  return {
3517
- pieces: fen.read(fen.initial),
3291
+ pieces: read(initial),
3518
3292
  orientation: 'white',
3519
3293
  turnColor: 'white',
3520
3294
  coordinates: true,
3521
3295
  autoCastle: true,
3522
3296
  viewOnly: false,
3523
3297
  disableContextMenu: false,
3524
- resizable: true,
3525
3298
  addPieceZIndex: false,
3299
+ addDimensionsCssVars: false,
3300
+ blockTouchScroll: false,
3526
3301
  pieceKey: false,
3527
3302
  highlight: {
3528
3303
  lastMove: true,
@@ -3553,7 +3328,6 @@ function defaults() {
3553
3328
  enabled: true,
3554
3329
  distance: 3,
3555
3330
  autoDistance: true,
3556
- centerPiece: true,
3557
3331
  showGhost: true,
3558
3332
  deleteOnDropOff: false
3559
3333
  },
@@ -3564,12 +3338,15 @@ function defaults() {
3564
3338
  enabled: true
3565
3339
  },
3566
3340
  stats: {
3341
+ // on touchscreen, default to "tap-tap" moves
3342
+ // instead of drag
3567
3343
  dragged: !('ontouchstart' in window)
3568
3344
  },
3569
3345
  events: {},
3570
3346
  drawable: {
3571
3347
  enabled: true,
3572
3348
  visible: true,
3349
+ defaultSnapToValidMove: true,
3573
3350
  eraseOnClick: true,
3574
3351
  shapes: [],
3575
3352
  autoShapes: [],
@@ -3628,36 +3405,22 @@ function defaults() {
3628
3405
  },
3629
3406
  prevSvgHash: ''
3630
3407
  },
3631
- hold: util.timer()
3408
+ hold: timer()
3632
3409
  };
3633
3410
  }
3634
3411
 
3635
- exports.defaults = defaults;
3636
- });
3637
-
3638
- var svg = createCommonjsModule(function (module, exports) {
3639
-
3640
- Object.defineProperty(exports, "__esModule", {
3641
- value: true
3642
- });
3643
-
3644
-
3645
-
3646
3412
  function createElement(tagName) {
3647
3413
  return document.createElementNS('http://www.w3.org/2000/svg', tagName);
3648
3414
  }
3649
-
3650
- exports.createElement = createElement;
3651
-
3652
- function renderSvg(state, root) {
3415
+ function renderSvg(state, svg, customSvg) {
3653
3416
  const d = state.drawable,
3654
3417
  curD = d.current,
3655
3418
  cur = curD && curD.mouseSq ? curD : undefined,
3656
- arrowDests = {},
3419
+ arrowDests = new Map(),
3657
3420
  bounds = state.dom.bounds();
3658
3421
 
3659
3422
  for (const s of d.shapes.concat(d.autoShapes).concat(cur ? [cur] : [])) {
3660
- if (s.dest) arrowDests[s.dest] = (arrowDests[s.dest] || 0) + 1;
3423
+ if (s.dest) arrowDests.set(s.dest, (arrowDests.get(s.dest) || 0) + 1);
3661
3424
  }
3662
3425
 
3663
3426
  const shapes = d.shapes.concat(d.autoShapes).map(s => {
@@ -3672,61 +3435,85 @@ function renderSvg(state, root) {
3672
3435
  current: true,
3673
3436
  hash: shapeHash(cur, arrowDests, true, bounds)
3674
3437
  });
3675
- const fullHash = shapes.map(sc => sc.hash).join('');
3438
+ const fullHash = shapes.map(sc => sc.hash).join(';');
3676
3439
  if (fullHash === state.drawable.prevSvgHash) return;
3677
3440
  state.drawable.prevSvgHash = fullHash;
3678
- const defsEl = root.firstChild;
3441
+ /*
3442
+ -- DOM hierarchy --
3443
+ <svg class="cg-shapes"> (<= svg)
3444
+ <defs>
3445
+ ...(for brushes)...
3446
+ </defs>
3447
+ <g>
3448
+ ...(for arrows, circles, and pieces)...
3449
+ </g>
3450
+ </svg>
3451
+ <svg class="cg-custom-svgs"> (<= customSvg)
3452
+ <g>
3453
+ ...(for custom svgs)...
3454
+ </g>
3455
+ </svg>
3456
+ */
3457
+
3458
+ const defsEl = svg.querySelector('defs');
3459
+ const shapesEl = svg.querySelector('g');
3460
+ const customSvgsEl = customSvg.querySelector('g');
3679
3461
  syncDefs(d, shapes, defsEl);
3680
- syncShapes(state, shapes, d.brushes, arrowDests, root, defsEl);
3681
- }
3682
-
3683
- exports.renderSvg = renderSvg;
3462
+ syncShapes(state, shapes.filter(s => !s.shape.customSvg), d.brushes, arrowDests, shapesEl);
3463
+ syncShapes(state, shapes.filter(s => s.shape.customSvg), d.brushes, arrowDests, customSvgsEl);
3464
+ } // append only. Don't try to update/remove.
3684
3465
 
3685
3466
  function syncDefs(d, shapes, defsEl) {
3686
- const brushes = {};
3467
+ const brushes = new Map();
3687
3468
  let brush;
3688
3469
 
3689
3470
  for (const s of shapes) {
3690
3471
  if (s.shape.dest) {
3691
3472
  brush = d.brushes[s.shape.brush];
3692
3473
  if (s.shape.modifiers) brush = makeCustomBrush(brush, s.shape.modifiers);
3693
- brushes[brush.key] = brush;
3474
+ brushes.set(brush.key, brush);
3694
3475
  }
3695
3476
  }
3696
3477
 
3697
- const keysInDom = {};
3478
+ const keysInDom = new Set();
3698
3479
  let el = defsEl.firstChild;
3699
3480
 
3700
3481
  while (el) {
3701
- keysInDom[el.getAttribute('cgKey')] = true;
3482
+ keysInDom.add(el.getAttribute('cgKey'));
3702
3483
  el = el.nextSibling;
3703
3484
  }
3704
3485
 
3705
- for (const key in brushes) {
3706
- if (!keysInDom[key]) defsEl.appendChild(renderMarker(brushes[key]));
3486
+ for (const [key, brush] of brushes.entries()) {
3487
+ if (!keysInDom.has(key)) defsEl.appendChild(renderMarker(brush));
3707
3488
  }
3708
- }
3489
+ } // append and remove only. No updates.
3490
+
3709
3491
 
3710
- function syncShapes(state, shapes, brushes, arrowDests, root, defsEl) {
3492
+ function syncShapes(state, shapes, brushes, arrowDests, root) {
3711
3493
  const bounds = state.dom.bounds(),
3712
- hashesInDom = {},
3713
- toRemove = [];
3494
+ hashesInDom = new Map(),
3495
+ // by hash
3496
+ toRemove = [];
3714
3497
 
3715
- for (const sc of shapes) hashesInDom[sc.hash] = false;
3498
+ for (const sc of shapes) hashesInDom.set(sc.hash, false);
3716
3499
 
3717
- let el = defsEl.nextSibling,
3500
+ let el = root.firstChild,
3718
3501
  elHash;
3719
3502
 
3720
3503
  while (el) {
3721
- elHash = el.getAttribute('cgHash');
3722
- if (hashesInDom.hasOwnProperty(elHash)) hashesInDom[elHash] = true;else toRemove.push(el);
3504
+ elHash = el.getAttribute('cgHash'); // found a shape element that's here to stay
3505
+
3506
+ if (hashesInDom.has(elHash)) hashesInDom.set(elHash, true); // or remove it
3507
+ else toRemove.push(el);
3723
3508
  el = el.nextSibling;
3724
- }
3509
+ } // remove old shapes
3510
+
3511
+
3512
+ for (const el of toRemove) root.removeChild(el); // insert shapes that are not yet in dom
3725
3513
 
3726
- for (const el of toRemove) root.removeChild(el);
3727
3514
 
3728
3515
  for (const sc of shapes) {
3729
- if (!hashesInDom[sc.hash]) root.appendChild(renderShape(state, sc, brushes, arrowDests, bounds));
3516
+ if (!hashesInDom.get(sc.hash)) root.appendChild(renderShape(state, sc, brushes, arrowDests, bounds));
3730
3517
  }
3731
3518
  }
3732
3519
 
@@ -3735,9 +3522,10 @@ function shapeHash({
3735
3522
  dest,
3736
3523
  brush,
3737
3524
  piece,
3738
- modifiers
3525
+ modifiers,
3526
+ customSvg
3739
3527
  }, arrowDests, current, bounds) {
3740
- return [bounds.width, bounds.height, current, orig, dest, brush, dest && arrowDests[dest] > 1, piece && pieceHash(piece), modifiers && modifiersHash(modifiers)].filter(x => x).join(',');
3528
+ return [bounds.width, bounds.height, current, orig, dest, brush, dest && (arrowDests.get(dest) || 0) > 1, piece && pieceHash(piece), modifiers && modifiersHash(modifiers), customSvg && customSvgHash(customSvg)].filter(x => x).join(',');
3741
3529
  }
3742
3530
 
3743
3531
  function pieceHash(piece) {
@@ -3748,29 +3536,62 @@ function modifiersHash(m) {
3748
3536
  return '' + (m.lineWidth || '');
3749
3537
  }
3750
3538
 
3539
+ function customSvgHash(s) {
3540
+ // Rolling hash with base 31 (cf. https://stackoverflow.com/questions/7616461/generate-a-hash-from-string-in-javascript)
3541
+ let h = 0;
3542
+
3543
+ for (let i = 0; i < s.length; i++) {
3544
+ h = (h << 5) - h + s.charCodeAt(i) >>> 0;
3545
+ }
3546
+
3547
+ return 'custom-' + h.toString();
3548
+ }
3549
+
3751
3550
  function renderShape(state, {
3752
3551
  shape,
3753
3552
  current,
3754
3553
  hash
3755
3554
  }, brushes, arrowDests, bounds) {
3756
3555
  let el;
3757
- if (shape.piece) el = renderPiece(state.drawable.pieces.baseUrl, orient(util.key2pos(shape.orig), state.orientation), shape.piece, bounds);else {
3758
- const orig = orient(util.key2pos(shape.orig), state.orientation);
3556
+
3557
+ if (shape.customSvg) {
3558
+ const orig = orient(key2pos(shape.orig), state.orientation);
3559
+ el = renderCustomSvg(shape.customSvg, orig, bounds);
3560
+ } else if (shape.piece) el = renderPiece(state.drawable.pieces.baseUrl, orient(key2pos(shape.orig), state.orientation), shape.piece, bounds);else {
3561
+ const orig = orient(key2pos(shape.orig), state.orientation);
3759
3562
 
3760
3563
  if (shape.dest) {
3761
3564
  let brush = brushes[shape.brush];
3762
3565
  if (shape.modifiers) brush = makeCustomBrush(brush, shape.modifiers);
3763
- el = renderArrow(brush, orig, orient(util.key2pos(shape.dest), state.orientation), current, arrowDests[shape.dest] > 1, bounds);
3566
+ el = renderArrow(brush, orig, orient(key2pos(shape.dest), state.orientation), current, (arrowDests.get(shape.dest) || 0) > 1, bounds);
3764
3567
  } else el = renderCircle(brushes[shape.brush], orig, current, bounds);
3765
3568
  }
3569
+
3766
3570
  el.setAttribute('cgHash', hash);
3767
3571
  return el;
3768
3572
  }
3769
3573
 
3574
+ function renderCustomSvg(customSvg, pos, bounds) {
3575
+ const [x, y] = pos2user(pos, bounds); // Translate to top-left of `orig` square
3576
+
3577
+ const g = setAttributes(createElement('g'), {
3578
+ transform: `translate(${x},${y})`
3579
+ }); // Give 100x100 coordinate system to the user for `orig` square
3580
+
3581
+ const svg = setAttributes(createElement('svg'), {
3582
+ width: 1,
3583
+ height: 1,
3584
+ viewBox: '0 0 100 100'
3585
+ });
3586
+ g.appendChild(svg);
3587
+ svg.innerHTML = customSvg;
3588
+ return g;
3589
+ }
3590
+
3770
3591
  function renderCircle(brush, pos, current, bounds) {
3771
- const o = pos2px(pos, bounds),
3772
- widths = circleWidth(bounds),
3773
- radius = (bounds.width + bounds.height) / 32;
3592
+ const o = pos2user(pos, bounds),
3593
+ widths = circleWidth(),
3594
+ radius = (bounds.width + bounds.height) / (4 * Math.max(bounds.width, bounds.height));
3774
3595
  return setAttributes(createElement('circle'), {
3775
3596
  stroke: brush.color,
3776
3597
  'stroke-width': widths[current ? 0 : 1],
@@ -3783,9 +3604,9 @@ function renderCircle(brush, pos, current, bounds) {
3783
3604
  }
3784
3605
 
3785
3606
  function renderArrow(brush, orig, dest, current, shorten, bounds) {
3786
- const m = arrowMargin(bounds, shorten && !current),
3787
- a = pos2px(orig, bounds),
3788
- b = pos2px(dest, bounds),
3607
+ const m = arrowMargin(shorten && !current),
3608
+ a = pos2user(orig, bounds),
3609
+ b = pos2user(dest, bounds),
3789
3610
  dx = b[0] - a[0],
3790
3611
  dy = b[1] - a[1],
3791
3612
  angle = Math.atan2(dy, dx),
@@ -3793,7 +3614,7 @@ function renderArrow(brush, orig, dest, current, shorten, bounds) {
3793
3614
  yo = Math.sin(angle) * m;
3794
3615
  return setAttributes(createElement('line'), {
3795
3616
  stroke: brush.color,
3796
- 'stroke-width': lineWidth(brush, current, bounds),
3617
+ 'stroke-width': lineWidth(brush, current),
3797
3618
  'stroke-linecap': 'round',
3798
3619
  'marker-end': 'url(#arrowhead-' + brush.key + ')',
3799
3620
  opacity: opacity(brush, current),
@@ -3805,16 +3626,17 @@ function renderArrow(brush, orig, dest, current, shorten, bounds) {
3805
3626
  }
3806
3627
 
3807
3628
  function renderPiece(baseUrl, pos, piece, bounds) {
3808
- const o = pos2px(pos, bounds),
3809
- size = bounds.width / 8 * (piece.scale || 1),
3629
+ const o = pos2user(pos, bounds),
3810
3630
  name = piece.color[0] + (piece.role === 'knight' ? 'n' : piece.role[0]).toUpperCase();
3811
3631
  return setAttributes(createElement('image'), {
3812
3632
  className: `${piece.role} ${piece.color}`,
3813
- x: o[0] - size / 2,
3814
- y: o[1] - size / 2,
3815
- width: size,
3816
- height: size,
3817
- href: baseUrl + name + '.svg'
3633
+ x: o[0] - 0.5,
3634
+ y: o[1] - 0.5,
3635
+ width: 1,
3636
+ height: 1,
3637
+ href: baseUrl + name + '.svg',
3638
+ transform: `scale(${piece.scale || 1})`,
3639
+ 'transform-origin': `${o[0]} ${o[1]}`
3818
3640
  });
3819
3641
  }
3820
3642
 
@@ -3842,179 +3664,147 @@ function setAttributes(el, attrs) {
3842
3664
  }
3843
3665
 
3844
3666
  function orient(pos, color) {
3845
- return color === 'white' ? pos : [9 - pos[0], 9 - pos[1]];
3667
+ return color === 'white' ? pos : [7 - pos[0], 7 - pos[1]];
3846
3668
  }
3847
3669
 
3848
3670
  function makeCustomBrush(base, modifiers) {
3849
- const brush = {
3671
+ return {
3850
3672
  color: base.color,
3851
3673
  opacity: Math.round(base.opacity * 10) / 10,
3852
- lineWidth: Math.round(modifiers.lineWidth || base.lineWidth)
3674
+ lineWidth: Math.round(modifiers.lineWidth || base.lineWidth),
3675
+ key: [base.key, modifiers.lineWidth].filter(x => x).join('')
3853
3676
  };
3854
- brush.key = [base.key, modifiers.lineWidth].filter(x => x).join('');
3855
- return brush;
3856
3677
  }
3857
3678
 
3858
- function circleWidth(bounds) {
3859
- const base = bounds.width / 512;
3860
- return [3 * base, 4 * base];
3679
+ function circleWidth() {
3680
+ return [3 / 64, 4 / 64];
3861
3681
  }
3862
3682
 
3863
- function lineWidth(brush, current, bounds) {
3864
- return (brush.lineWidth || 10) * (current ? 0.85 : 1) / 512 * bounds.width;
3683
+ function lineWidth(brush, current) {
3684
+ return (brush.lineWidth || 10) * (current ? 0.85 : 1) / 64;
3865
3685
  }
3866
3686
 
3867
3687
  function opacity(brush, current) {
3868
3688
  return (brush.opacity || 1) * (current ? 0.9 : 1);
3869
3689
  }
3870
3690
 
3871
- function arrowMargin(bounds, shorten) {
3872
- return (shorten ? 20 : 10) / 512 * bounds.width;
3691
+ function arrowMargin(shorten) {
3692
+ return (shorten ? 20 : 10) / 64;
3873
3693
  }
3874
3694
 
3875
- function pos2px(pos, bounds) {
3876
- return [(pos[0] - 0.5) * bounds.width / 8, (8.5 - pos[1]) * bounds.height / 8];
3695
+ function pos2user(pos, bounds) {
3696
+ const xScale = Math.min(1, bounds.width / bounds.height);
3697
+ const yScale = Math.min(1, bounds.height / bounds.width);
3698
+ return [(pos[0] - 3.5) * xScale, (3.5 - pos[1]) * yScale];
3877
3699
  }
3878
- });
3879
-
3880
- var wrap_1 = createCommonjsModule(function (module, exports) {
3881
-
3882
- Object.defineProperty(exports, "__esModule", {
3883
- value: true
3884
- });
3885
3700
 
3701
+ function renderWrap(element, s) {
3702
+ // .cg-wrap (element passed to Chessground)
3703
+ // cg-container
3704
+ // cg-board
3705
+ // svg.cg-shapes
3706
+ // defs
3707
+ // g
3708
+ // svg.cg-custom-svgs
3709
+ // g
3710
+ // coords.ranks
3711
+ // coords.files
3712
+ // piece.ghost
3713
+ element.innerHTML = ''; // ensure the cg-wrap class is set
3714
+ // so bounds calculation can use the CSS width/height values
3715
+ // add that class yourself to the element before calling chessground
3716
+ // for a slight performance improvement! (avoids recomputing style)
3886
3717
 
3887
-
3888
-
3889
-
3890
-
3891
-
3892
- function wrap(element, s, relative) {
3893
- element.innerHTML = '';
3894
3718
  element.classList.add('cg-wrap');
3895
3719
 
3896
- for (const c of util.colors) element.classList.toggle('orientation-' + c, s.orientation === c);
3720
+ for (const c of colors) element.classList.toggle('orientation-' + c, s.orientation === c);
3897
3721
 
3898
3722
  element.classList.toggle('manipulable', !s.viewOnly);
3899
- const helper = util.createEl('cg-helper');
3900
- element.appendChild(helper);
3901
- const container = util.createEl('cg-container');
3902
- helper.appendChild(container);
3903
- const board = util.createEl('cg-board');
3723
+ const container = createEl('cg-container');
3724
+ element.appendChild(container);
3725
+ const board = createEl('cg-board');
3904
3726
  container.appendChild(board);
3905
- let svg$1;
3906
-
3907
- if (s.drawable.visible && !relative) {
3908
- svg$1 = svg.createElement('svg');
3909
- svg$1.appendChild(svg.createElement('defs'));
3910
- container.appendChild(svg$1);
3727
+ let svg;
3728
+ let customSvg;
3729
+
3730
+ if (s.drawable.visible) {
3731
+ svg = setAttributes(createElement('svg'), {
3732
+ class: 'cg-shapes',
3733
+ viewBox: '-4 -4 8 8',
3734
+ preserveAspectRatio: 'xMidYMid slice'
3735
+ });
3736
+ svg.appendChild(createElement('defs'));
3737
+ svg.appendChild(createElement('g'));
3738
+ customSvg = setAttributes(createElement('svg'), {
3739
+ class: 'cg-custom-svgs',
3740
+ viewBox: '-3.5 -3.5 8 8',
3741
+ preserveAspectRatio: 'xMidYMid slice'
3742
+ });
3743
+ customSvg.appendChild(createElement('g'));
3744
+ container.appendChild(svg);
3745
+ container.appendChild(customSvg);
3911
3746
  }
3912
3747
 
3913
3748
  if (s.coordinates) {
3914
3749
  const orientClass = s.orientation === 'black' ? ' black' : '';
3915
- container.appendChild(renderCoords(types.ranks.map(r => r.toString()), 'ranks' + orientClass));
3916
- container.appendChild(renderCoords(types.files, 'files' + orientClass));
3750
+ container.appendChild(renderCoords(ranks, 'ranks' + orientClass));
3751
+ container.appendChild(renderCoords(files, 'files' + orientClass));
3917
3752
  }
3918
3753
 
3919
3754
  let ghost;
3920
3755
 
3921
- if (s.draggable.showGhost && !relative) {
3922
- ghost = util.createEl('piece', 'ghost');
3923
- util.setVisible(ghost, false);
3756
+ if (s.draggable.showGhost) {
3757
+ ghost = createEl('piece', 'ghost');
3758
+ setVisible(ghost, false);
3924
3759
  container.appendChild(ghost);
3925
3760
  }
3926
3761
 
3927
3762
  return {
3928
3763
  board,
3929
3764
  container,
3765
+ wrap: element,
3930
3766
  ghost,
3931
- svg: svg$1
3767
+ svg,
3768
+ customSvg
3932
3769
  };
3933
3770
  }
3934
3771
 
3935
- exports.default = wrap;
3936
-
3937
3772
  function renderCoords(elems, className) {
3938
- const el = util.createEl('coords', className);
3773
+ const el = createEl('coords', className);
3939
3774
  let f;
3940
3775
 
3941
3776
  for (const elem of elems) {
3942
- f = util.createEl('coord');
3777
+ f = createEl('coord');
3943
3778
  f.textContent = elem;
3944
3779
  el.appendChild(f);
3945
3780
  }
3946
3781
 
3947
3782
  return el;
3948
3783
  }
3949
- });
3950
-
3951
- var drop_1 = createCommonjsModule(function (module, exports) {
3952
-
3953
- Object.defineProperty(exports, "__esModule", {
3954
- value: true
3955
- });
3956
-
3957
-
3958
-
3959
-
3960
-
3961
-
3962
-
3963
- function setDropMode(s, piece) {
3964
- s.dropmode = {
3965
- active: true,
3966
- piece
3967
- };
3968
- drag.cancel(s);
3969
- }
3970
-
3971
- exports.setDropMode = setDropMode;
3972
-
3973
- function cancelDropMode(s) {
3974
- s.dropmode = {
3975
- active: false
3976
- };
3977
- }
3978
-
3979
- exports.cancelDropMode = cancelDropMode;
3980
3784
 
3981
3785
  function drop(s, e) {
3982
3786
  if (!s.dropmode.active) return;
3983
- board.unsetPremove(s);
3984
- board.unsetPredrop(s);
3787
+ unsetPremove(s);
3788
+ unsetPredrop(s);
3985
3789
  const piece = s.dropmode.piece;
3986
3790
 
3987
3791
  if (piece) {
3988
- s.pieces.a0 = piece;
3989
- const position = util.eventPosition(e);
3990
- const dest = position && board.getKeyAtDomPos(position, board.whitePov(s), s.dom.bounds());
3991
- if (dest) board.dropNewPiece(s, 'a0', dest);
3792
+ s.pieces.set('a0', piece);
3793
+ const position = eventPosition(e);
3794
+ const dest = position && getKeyAtDomPos(position, whitePov(s), s.dom.bounds());
3795
+ if (dest) dropNewPiece(s, 'a0', dest);
3992
3796
  }
3993
3797
 
3994
3798
  s.dom.redraw();
3995
3799
  }
3996
3800
 
3997
- exports.drop = drop;
3998
- });
3999
-
4000
- var events = createCommonjsModule(function (module, exports) {
4001
-
4002
- Object.defineProperty(exports, "__esModule", {
4003
- value: true
4004
- });
4005
-
4006
-
4007
-
4008
-
3801
+ function bindBoard(s, onResize) {
3802
+ const boardEl = s.dom.elements.board;
3803
+ if ('ResizeObserver' in window) new ResizeObserver(onResize).observe(s.dom.elements.wrap);
3804
+ if (s.viewOnly) return; // Cannot be passive, because we prevent touch scrolling and dragging of
3805
+ // selected elements.
4009
3806
 
4010
-
4011
-
4012
-
4013
-
4014
- function bindBoard(s, boundsUpdated) {
4015
- if (s.viewOnly) return;
4016
- const boardEl = s.dom.elements.board,
4017
- onStart = startDragOrDraw(s);
3807
+ const onStart = startDragOrDraw(s);
4018
3808
  boardEl.addEventListener('touchstart', onStart, {
4019
3809
  passive: false
4020
3810
  });
@@ -4025,25 +3815,17 @@ function bindBoard(s, boundsUpdated) {
4025
3815
  if (s.disableContextMenu || s.drawable.enabled) {
4026
3816
  boardEl.addEventListener('contextmenu', e => e.preventDefault());
4027
3817
  }
3818
+ } // returns the unbind function
4028
3819
 
4029
- if (!s.dom.relative && s.resizable && 'ResizeObserver' in window) {
4030
- const observer = new window['ResizeObserver'](boundsUpdated);
4031
- observer.observe(boardEl);
4032
- }
4033
- }
4034
-
4035
- exports.bindBoard = bindBoard;
3820
+ function bindDocument(s, onResize) {
3821
+ const unbinds = []; // Old versions of Edge and Safari do not support ResizeObserver. Send
3822
+ // chessground.resize if a user action has changed the bounds of the board.
4036
3823
 
4037
- function bindDocument(s, boundsUpdated) {
4038
- const unbinds = [];
4039
-
4040
- if (!s.dom.relative && s.resizable && !('ResizeObserver' in window)) {
4041
- unbinds.push(unbindable(document.body, 'chessground.resize', boundsUpdated));
4042
- }
3824
+ if (!('ResizeObserver' in window)) unbinds.push(unbindable(document.body, 'chessground.resize', onResize));
4043
3825
 
4044
3826
  if (!s.viewOnly) {
4045
- const onmove = dragOrDraw(s, drag.move, draw.move);
4046
- const onend = dragOrDraw(s, drag.end, draw.end);
3827
+ const onmove = dragOrDraw(s, move$1, move);
3828
+ const onend = dragOrDraw(s, end$1, end);
4047
3829
 
4048
3830
  for (const ev of ['touchmove', 'mousemove']) unbinds.push(unbindable(document, ev, onmove));
4049
3831
 
@@ -4063,8 +3845,6 @@ function bindDocument(s, boundsUpdated) {
4063
3845
  return () => unbinds.forEach(f => f());
4064
3846
  }
4065
3847
 
4066
- exports.bindDocument = bindDocument;
4067
-
4068
3848
  function unbindable(el, eventName, callback, options) {
4069
3849
  el.addEventListener(eventName, callback, options);
4070
3850
  return () => el.removeEventListener(eventName, callback, options);
@@ -4072,136 +3852,136 @@ function unbindable(el, eventName, callback, options) {
4072
3852
 
4073
3853
  function startDragOrDraw(s) {
4074
3854
  return e => {
4075
- if (s.draggable.current) drag.cancel(s);else if (s.drawable.current) draw.cancel(s);else if (e.shiftKey || util.isRightButton(e)) {
4076
- if (s.drawable.enabled) draw.start(s, e);
3855
+ if (s.draggable.current) cancel$1(s);else if (s.drawable.current) cancel(s);else if (e.shiftKey || isRightButton(e)) {
3856
+ if (s.drawable.enabled) start(s, e);
4077
3857
  } else if (!s.viewOnly) {
4078
- if (s.dropmode.active) drop_1.drop(s, e);else drag.start(s, e);
3858
+ if (s.dropmode.active) drop(s, e);else start$1(s, e);
4079
3859
  }
4080
3860
  };
4081
3861
  }
4082
3862
 
4083
3863
  function dragOrDraw(s, withDrag, withDraw) {
4084
3864
  return e => {
4085
- if (e.shiftKey || util.isRightButton(e)) {
3865
+ if (s.drawable.current) {
4086
3866
  if (s.drawable.enabled) withDraw(s, e);
4087
3867
  } else if (!s.viewOnly) withDrag(s, e);
4088
3868
  };
4089
3869
  }
4090
- });
4091
-
4092
- var render_1 = createCommonjsModule(function (module, exports) {
4093
-
4094
- Object.defineProperty(exports, "__esModule", {
4095
- value: true
4096
- });
4097
3870
 
3871
+ // in case of bugs, blame @veloce
4098
3872
 
4099
-
4100
-
4101
-
4102
- const util$1 = util;
4103
-
4104
- function render(s) {
4105
- const asWhite = board.whitePov(s),
4106
- posToTranslate = s.dom.relative ? util$1.posToTranslateRel : util$1.posToTranslateAbs(s.dom.bounds()),
4107
- translate = s.dom.relative ? util$1.translateRel : util$1.translateAbs,
3873
+ function render$1(s) {
3874
+ const asWhite = whitePov(s),
3875
+ posToTranslate$1 = posToTranslate(s.dom.bounds()),
4108
3876
  boardEl = s.dom.elements.board,
4109
3877
  pieces = s.pieces,
4110
3878
  curAnim = s.animation.current,
4111
- anims = curAnim ? curAnim.plan.anims : {},
4112
- fadings = curAnim ? curAnim.plan.fadings : {},
3879
+ anims = curAnim ? curAnim.plan.anims : new Map(),
3880
+ fadings = curAnim ? curAnim.plan.fadings : new Map(),
4113
3881
  curDrag = s.draggable.current,
4114
3882
  squares = computeSquareClasses(s),
4115
- samePieces = {},
4116
- sameSquares = {},
4117
- movedPieces = {},
4118
- movedSquares = {},
4119
- piecesKeys = Object.keys(pieces);
4120
- let k, p, el, pieceAtKey, elPieceName, anim, fading, pMvdset, pMvd, sMvdset, sMvd;
3883
+ samePieces = new Set(),
3884
+ sameSquares = new Set(),
3885
+ movedPieces = new Map(),
3886
+ movedSquares = new Map(); // by class name
3887
+
3888
+ let k, el, pieceAtKey, elPieceName, anim, fading, pMvdset, pMvd, sMvdset, sMvd; // walk over all board dom elements, apply animations and flag moved pieces
3889
+
4121
3890
  el = boardEl.firstChild;
4122
3891
 
4123
3892
  while (el) {
4124
3893
  k = el.cgKey;
4125
3894
 
4126
3895
  if (isPieceNode(el)) {
4127
- pieceAtKey = pieces[k];
4128
- anim = anims[k];
4129
- fading = fadings[k];
4130
- elPieceName = el.cgPiece;
3896
+ pieceAtKey = pieces.get(k);
3897
+ anim = anims.get(k);
3898
+ fading = fadings.get(k);
3899
+ elPieceName = el.cgPiece; // if piece not being dragged anymore, remove dragging style
4131
3900
 
4132
3901
  if (el.cgDragging && (!curDrag || curDrag.orig !== k)) {
4133
3902
  el.classList.remove('dragging');
4134
- translate(el, posToTranslate(util.key2pos(k), asWhite));
3903
+ translate(el, posToTranslate$1(key2pos(k), asWhite));
4135
3904
  el.cgDragging = false;
4136
- }
3905
+ } // remove fading class if it still remains
3906
+
4137
3907
 
4138
3908
  if (!fading && el.cgFading) {
4139
3909
  el.cgFading = false;
4140
3910
  el.classList.remove('fading');
4141
- }
3911
+ } // there is now a piece at this dom key
3912
+
4142
3913
 
4143
3914
  if (pieceAtKey) {
3915
+ // continue animation if already animating and same piece
3916
+ // (otherwise it could animate a captured piece)
4144
3917
  if (anim && el.cgAnimating && elPieceName === pieceNameOf(pieceAtKey)) {
4145
- const pos = util.key2pos(k);
3918
+ const pos = key2pos(k);
4146
3919
  pos[0] += anim[2];
4147
3920
  pos[1] += anim[3];
4148
3921
  el.classList.add('anim');
4149
- translate(el, posToTranslate(pos, asWhite));
3922
+ translate(el, posToTranslate$1(pos, asWhite));
4150
3923
  } else if (el.cgAnimating) {
4151
3924
  el.cgAnimating = false;
4152
3925
  el.classList.remove('anim');
4153
- translate(el, posToTranslate(util.key2pos(k), asWhite));
4154
- if (s.addPieceZIndex) el.style.zIndex = posZIndex(util.key2pos(k), asWhite);
4155
- }
3926
+ translate(el, posToTranslate$1(key2pos(k), asWhite));
3927
+ if (s.addPieceZIndex) el.style.zIndex = posZIndex(key2pos(k), asWhite);
3928
+ } // same piece: flag as same
3929
+
4156
3930
 
4157
3931
  if (elPieceName === pieceNameOf(pieceAtKey) && (!fading || !el.cgFading)) {
4158
- samePieces[k] = true;
4159
- } else {
4160
- if (fading && elPieceName === pieceNameOf(fading)) {
4161
- el.classList.add('fading');
4162
- el.cgFading = true;
4163
- } else {
4164
- if (movedPieces[elPieceName]) movedPieces[elPieceName].push(el);else movedPieces[elPieceName] = [el];
3932
+ samePieces.add(k);
3933
+ } // different piece: flag as moved unless it is a fading piece
3934
+ else {
3935
+ if (fading && elPieceName === pieceNameOf(fading)) {
3936
+ el.classList.add('fading');
3937
+ el.cgFading = true;
3938
+ } else {
3939
+ appendValue(movedPieces, elPieceName, el);
3940
+ }
4165
3941
  }
3942
+ } // no piece: flag as moved
3943
+ else {
3944
+ appendValue(movedPieces, elPieceName, el);
4166
3945
  }
4167
- } else {
4168
- if (movedPieces[elPieceName]) movedPieces[elPieceName].push(el);else movedPieces[elPieceName] = [el];
4169
- }
4170
3946
  } else if (isSquareNode(el)) {
4171
3947
  const cn = el.className;
4172
- if (squares[k] === cn) sameSquares[k] = true;else if (movedSquares[cn]) movedSquares[cn].push(el);else movedSquares[cn] = [el];
3948
+ if (squares.get(k) === cn) sameSquares.add(k);else appendValue(movedSquares, cn, el);
4173
3949
  }
4174
3950
 
4175
3951
  el = el.nextSibling;
4176
- }
3952
+ } // walk over all squares in current set, apply dom changes to moved squares
3953
+ // or append new squares
3954
+
4177
3955
 
4178
- for (const sk in squares) {
4179
- if (!sameSquares[sk]) {
4180
- sMvdset = movedSquares[squares[sk]];
3956
+ for (const [sk, className] of squares) {
3957
+ if (!sameSquares.has(sk)) {
3958
+ sMvdset = movedSquares.get(className);
4181
3959
  sMvd = sMvdset && sMvdset.pop();
4182
- const translation = posToTranslate(util.key2pos(sk), asWhite);
3960
+ const translation = posToTranslate$1(key2pos(sk), asWhite);
4183
3961
 
4184
3962
  if (sMvd) {
4185
3963
  sMvd.cgKey = sk;
4186
3964
  translate(sMvd, translation);
4187
3965
  } else {
4188
- const squareNode = util.createEl('square', squares[sk]);
3966
+ const squareNode = createEl('square', className);
4189
3967
  squareNode.cgKey = sk;
4190
3968
  translate(squareNode, translation);
4191
3969
  boardEl.insertBefore(squareNode, boardEl.firstChild);
4192
3970
  }
4193
3971
  }
4194
- }
3972
+ } // walk over all pieces in current set, apply dom changes to moved pieces
3973
+ // or append new pieces
3974
+
4195
3975
 
4196
- for (k of piecesKeys) {
4197
- p = pieces[k];
4198
- anim = anims[k];
3976
+ for (const [k, p] of pieces) {
3977
+ anim = anims.get(k);
4199
3978
 
4200
- if (!samePieces[k]) {
4201
- pMvdset = movedPieces[pieceNameOf(p)];
4202
- pMvd = pMvdset && pMvdset.pop();
3979
+ if (!samePieces.has(k)) {
3980
+ pMvdset = movedPieces.get(pieceNameOf(p));
3981
+ pMvd = pMvdset && pMvdset.pop(); // a same piece was moved
4203
3982
 
4204
3983
  if (pMvd) {
3984
+ // apply dom changes
4205
3985
  pMvd.cgKey = k;
4206
3986
 
4207
3987
  if (pMvd.cgFading) {
@@ -4209,7 +3989,7 @@ function render(s) {
4209
3989
  pMvd.cgFading = false;
4210
3990
  }
4211
3991
 
4212
- const pos = util.key2pos(k);
3992
+ const pos = key2pos(k);
4213
3993
  if (s.addPieceZIndex) pMvd.style.zIndex = posZIndex(pos, asWhite);
4214
3994
 
4215
3995
  if (anim) {
@@ -4219,50 +3999,62 @@ function render(s) {
4219
3999
  pos[1] += anim[3];
4220
4000
  }
4221
4001
 
4222
- translate(pMvd, posToTranslate(pos, asWhite));
4223
- } else {
4224
- const pieceName = pieceNameOf(p),
4225
- pieceNode = util.createEl('piece', pieceName),
4226
- pos = util.key2pos(k);
4227
- pieceNode.cgPiece = pieceName;
4228
- pieceNode.cgKey = k;
4002
+ translate(pMvd, posToTranslate$1(pos, asWhite));
4003
+ } // no piece in moved obj: insert the new piece
4004
+ // assumes the new piece is not being dragged
4005
+ else {
4006
+ const pieceName = pieceNameOf(p),
4007
+ pieceNode = createEl('piece', pieceName),
4008
+ pos = key2pos(k);
4009
+ pieceNode.cgPiece = pieceName;
4010
+ pieceNode.cgKey = k;
4011
+
4012
+ if (anim) {
4013
+ pieceNode.cgAnimating = true;
4014
+ pos[0] += anim[2];
4015
+ pos[1] += anim[3];
4016
+ }
4229
4017
 
4230
- if (anim) {
4231
- pieceNode.cgAnimating = true;
4232
- pos[0] += anim[2];
4233
- pos[1] += anim[3];
4018
+ translate(pieceNode, posToTranslate$1(pos, asWhite));
4019
+ if (s.addPieceZIndex) pieceNode.style.zIndex = posZIndex(pos, asWhite);
4020
+ boardEl.appendChild(pieceNode);
4234
4021
  }
4235
-
4236
- translate(pieceNode, posToTranslate(pos, asWhite));
4237
- if (s.addPieceZIndex) pieceNode.style.zIndex = posZIndex(pos, asWhite);
4238
- boardEl.appendChild(pieceNode);
4239
- }
4240
4022
  }
4241
- }
4023
+ } // remove any element that remains in the moved sets
4242
4024
 
4243
- for (const i in movedPieces) removeNodes(s, movedPieces[i]);
4244
4025
 
4245
- for (const i in movedSquares) removeNodes(s, movedSquares[i]);
4246
- }
4026
+ for (const nodes of movedPieces.values()) removeNodes(s, nodes);
4247
4027
 
4248
- exports.render = render;
4249
-
4250
- function updateBounds(s) {
4251
- if (s.dom.relative) return;
4252
- const asWhite = board.whitePov(s),
4253
- posToTranslate = util$1.posToTranslateAbs(s.dom.bounds());
4028
+ for (const nodes of movedSquares.values()) removeNodes(s, nodes);
4029
+ }
4030
+ function renderResized(s) {
4031
+ const asWhite = whitePov(s),
4032
+ posToTranslate$1 = posToTranslate(s.dom.bounds());
4254
4033
  let el = s.dom.elements.board.firstChild;
4255
4034
 
4256
4035
  while (el) {
4257
4036
  if (isPieceNode(el) && !el.cgAnimating || isSquareNode(el)) {
4258
- util$1.translateAbs(el, posToTranslate(util.key2pos(el.cgKey), asWhite));
4037
+ translate(el, posToTranslate$1(key2pos(el.cgKey), asWhite));
4259
4038
  }
4260
4039
 
4261
4040
  el = el.nextSibling;
4262
4041
  }
4263
4042
  }
4043
+ function updateBounds(s) {
4044
+ const bounds = s.dom.elements.wrap.getBoundingClientRect();
4045
+ const container = s.dom.elements.container;
4046
+ const ratio = bounds.height / bounds.width;
4047
+ const width = Math.floor(bounds.width * window.devicePixelRatio / 8) * 8 / window.devicePixelRatio;
4048
+ const height = width * ratio;
4049
+ container.style.width = width + 'px';
4050
+ container.style.height = height + 'px';
4051
+ s.dom.bounds.clear();
4264
4052
 
4265
- exports.updateBounds = updateBounds;
4053
+ if (s.addDimensionsCssVars) {
4054
+ document.documentElement.style.setProperty('--cg-width', width + 'px');
4055
+ document.documentElement.style.setProperty('--cg-height', height + 'px');
4056
+ }
4057
+ }
4266
4058
 
4267
4059
  function isPieceNode(el) {
4268
4060
  return el.tagName === 'PIECE';
@@ -4277,8 +4069,8 @@ function removeNodes(s, nodes) {
4277
4069
  }
4278
4070
 
4279
4071
  function posZIndex(pos, asWhite) {
4280
- let z = 2 + (pos[1] - 1) * 8 + (8 - pos[0]);
4281
- if (asWhite) z = 67 - z;
4072
+ let z = 3 + pos[1] * 8 + (7 - pos[0]);
4073
+ if (asWhite) z = 69 - z;
4282
4074
  return z + '';
4283
4075
  }
4284
4076
 
@@ -4287,7 +4079,9 @@ function pieceNameOf(piece) {
4287
4079
  }
4288
4080
 
4289
4081
  function computeSquareClasses(s) {
4290
- const squares = {};
4082
+ var _a;
4083
+
4084
+ const squares = new Map();
4291
4085
  if (s.lastMove && s.highlight.lastMove) for (const k of s.lastMove) {
4292
4086
  addSquare(squares, k, 'last-move');
4293
4087
  }
@@ -4297,13 +4091,13 @@ function computeSquareClasses(s) {
4297
4091
  addSquare(squares, s.selected, 'selected');
4298
4092
 
4299
4093
  if (s.movable.showDests) {
4300
- const dests = s.movable.dests && s.movable.dests[s.selected];
4094
+ const dests = (_a = s.movable.dests) === null || _a === void 0 ? void 0 : _a.get(s.selected);
4301
4095
  if (dests) for (const k of dests) {
4302
- addSquare(squares, k, 'move-dest' + (s.pieces[k] ? ' oc' : ''));
4096
+ addSquare(squares, k, 'move-dest' + (s.pieces.has(k) ? ' oc' : ''));
4303
4097
  }
4304
4098
  const pDests = s.premovable.dests;
4305
4099
  if (pDests) for (const k of pDests) {
4306
- addSquare(squares, k, 'premove-dest' + (s.pieces[k] ? ' oc' : ''));
4100
+ addSquare(squares, k, 'premove-dest' + (s.pieces.has(k) ? ' oc' : ''));
4307
4101
  }
4308
4102
  }
4309
4103
  }
@@ -4316,73 +4110,54 @@ function computeSquareClasses(s) {
4316
4110
  }
4317
4111
 
4318
4112
  function addSquare(squares, key, klass) {
4319
- if (squares[key]) squares[key] += ' ' + klass;else squares[key] = klass;
4113
+ const classes = squares.get(key);
4114
+ if (classes) squares.set(key, `${classes} ${klass}`);else squares.set(key, klass);
4320
4115
  }
4321
- });
4322
-
4323
- var chessground = createCommonjsModule(function (module, exports) {
4324
-
4325
- Object.defineProperty(exports, "__esModule", {
4326
- value: true
4327
- });
4328
-
4329
-
4330
-
4331
-
4332
-
4333
-
4334
-
4335
-
4336
-
4337
-
4338
-
4339
-
4340
-
4341
-
4342
-
4343
4116
 
4117
+ function appendValue(map, key, value) {
4118
+ const arr = map.get(key);
4119
+ if (arr) arr.push(value);else map.set(key, [value]);
4120
+ }
4344
4121
 
4345
- function Chessground(element, config$1) {
4346
- const state$1 = state.defaults();
4347
- config.configure(state$1, config$1 || {});
4122
+ function Chessground(element, config) {
4123
+ const maybeState = defaults();
4124
+ configure(maybeState, config || {});
4348
4125
 
4349
4126
  function redrawAll() {
4350
- const prevUnbind = state$1.dom && state$1.dom.unbind;
4127
+ const prevUnbind = 'dom' in maybeState ? maybeState.dom.unbind : undefined; // compute bounds from existing board element if possible
4128
+ // this allows non-square boards from CSS to be handled (for 3D)
4351
4129
 
4352
- const relative = state$1.viewOnly && !state$1.drawable.visible,
4353
- elements = wrap_1.default(element, state$1, relative),
4354
- bounds = util.memo(() => elements.board.getBoundingClientRect()),
4130
+ const elements = renderWrap(element, maybeState),
4131
+ bounds = memo(() => elements.board.getBoundingClientRect()),
4355
4132
  redrawNow = skipSvg => {
4356
- render_1.render(state$1);
4357
- if (!skipSvg && elements.svg) svg.renderSvg(state$1, elements.svg);
4133
+ render$1(state);
4134
+ if (!skipSvg && elements.svg) renderSvg(state, elements.svg, elements.customSvg);
4358
4135
  },
4359
- boundsUpdated = () => {
4360
- bounds.clear();
4361
- render_1.updateBounds(state$1);
4362
- if (elements.svg) svg.renderSvg(state$1, elements.svg);
4136
+ onResize = () => {
4137
+ updateBounds(state);
4138
+ renderResized(state);
4363
4139
  };
4364
4140
 
4365
- state$1.dom = {
4141
+ const state = maybeState;
4142
+ state.dom = {
4366
4143
  elements,
4367
4144
  bounds,
4368
4145
  redraw: debounceRedraw(redrawNow),
4369
4146
  redrawNow,
4370
- unbind: prevUnbind,
4371
- relative
4147
+ unbind: prevUnbind
4372
4148
  };
4373
- state$1.drawable.prevSvgHash = '';
4149
+ state.drawable.prevSvgHash = '';
4150
+ updateBounds(state);
4374
4151
  redrawNow(false);
4375
- events.bindBoard(state$1, boundsUpdated);
4376
- if (!prevUnbind) state$1.dom.unbind = events.bindDocument(state$1, boundsUpdated);
4377
- state$1.events.insert && state$1.events.insert(elements);
4152
+ bindBoard(state, onResize);
4153
+ if (!prevUnbind) state.dom.unbind = bindDocument(state, onResize);
4154
+ state.events.insert && state.events.insert(elements);
4155
+ return state;
4378
4156
  }
4379
4157
 
4380
- redrawAll();
4381
- return api.start(state$1, redrawAll);
4158
+ return start$2(redrawAll(), redrawAll);
4382
4159
  }
4383
4160
 
4384
- exports.Chessground = Chessground;
4385
-
4386
4161
  function debounceRedraw(redrawNow) {
4387
4162
  let redrawing = false;
4388
4163
  return () => {
@@ -4394,14 +4169,13 @@ function debounceRedraw(redrawNow) {
4394
4169
  });
4395
4170
  };
4396
4171
  }
4397
- });
4398
4172
 
4399
- class Chessground extends React.Component {
4173
+ class Chessground$1 extends React.Component {
4400
4174
  buildConfigFromProps(props) {
4401
4175
  const config = {
4402
4176
  events: {}
4403
4177
  };
4404
- Object.keys(Chessground.types).forEach(k => {
4178
+ Object.keys(Chessground$1.types).forEach(k => {
4405
4179
  const v = props[k];
4406
4180
 
4407
4181
  if (typeof v !== 'undefined') {
@@ -4418,7 +4192,7 @@ class Chessground extends React.Component {
4418
4192
  }
4419
4193
 
4420
4194
  componentDidMount() {
4421
- this.board = chessground.Chessground(this.el, this.buildConfigFromProps(this.props));
4195
+ this.board = Chessground(this.el, this.buildConfigFromProps(this.props));
4422
4196
 
4423
4197
  if (this.props.shapes) {
4424
4198
  this.board.setShapes(this.props.shapes);
@@ -4426,7 +4200,7 @@ class Chessground extends React.Component {
4426
4200
  }
4427
4201
 
4428
4202
  componentDidUpdate() {
4429
- this.board = chessground.Chessground(this.el, this.buildConfigFromProps(this.props));
4203
+ this.board = Chessground(this.el, this.buildConfigFromProps(this.props));
4430
4204
 
4431
4205
  if (this.props.shapes) {
4432
4206
  this.board.setShapes(this.props.shapes);
@@ -4454,7 +4228,7 @@ class Chessground extends React.Component {
4454
4228
 
4455
4229
  }
4456
4230
 
4457
- _defineProperty(Chessground, "types", {
4231
+ _defineProperty(Chessground$1, "types", {
4458
4232
  width: propTypes.oneOfType([propTypes.string, propTypes.number]),
4459
4233
  height: propTypes.oneOfType([propTypes.string, propTypes.number]),
4460
4234
  fen: propTypes.string,
@@ -4484,7 +4258,7 @@ _defineProperty(Chessground, "types", {
4484
4258
  drawable: propTypes.object
4485
4259
  });
4486
4260
 
4487
- _defineProperty(Chessground, "defaultProps", {
4261
+ _defineProperty(Chessground$1, "defaultProps", {
4488
4262
  coordinates: false,
4489
4263
  resizable: true,
4490
4264
  hightlight: {
@@ -4534,13 +4308,16 @@ const audio = sound => {
4534
4308
  * @param {*} chess
4535
4309
  */
4536
4310
  const toDests = chess => {
4537
- const dests = {};
4311
+ const dests = new Map();
4538
4312
  chess.SQUARES.forEach(s => {
4539
4313
  const ms = chess.moves({
4540
4314
  square: s,
4541
4315
  verbose: true
4542
4316
  });
4543
- if (ms.length) dests[s] = ms.map(m => m.to);
4317
+
4318
+ if (ms.length) {
4319
+ dests.set(s, ms.map(m => m.to));
4320
+ }
4544
4321
  });
4545
4322
  const color = chess.turn() === 'w' ? 'white' : 'black';
4546
4323
  return {
@@ -6571,18 +6348,21 @@ var Chess = function (fen) {
6571
6348
  exports.Chess = Chess;
6572
6349
  });
6573
6350
 
6574
- const fen$1 = {
6351
+ const fen = {
6575
6352
  initial: 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1',
6576
6353
  empty: '8/8/8/8/8/8/8/8 w - - 0 1'
6577
6354
  };
6578
- const initial = fen$1.initial;
6355
+ const initial$1 = fen.initial;
6579
6356
 
6580
6357
  const useChess = props => {
6581
- const [fen, setFen] = useState(props.fen || initial);
6358
+ const [fen, setFen] = useState(props.fen || initial$1);
6582
6359
  const [chess$1] = useState(new chess.Chess(fen));
6583
6360
  const [lastMove, setLastMove] = useState([]);
6584
6361
  const turnColor = chess$1.turn() === 'w' ? 'white' : 'black';
6585
6362
  const [orientation] = useState(props.orientation || turnColor);
6363
+ const [sideToMove] = useState(turnColor);
6364
+ const autoQueen = props.options && props.options.autoQueen;
6365
+ const promotion = autoQueen && turnColor !== sideToMove ? 'q' : '';
6586
6366
 
6587
6367
  const onMove = (from, to, promotion) => {
6588
6368
  const move = chess$1.move({
@@ -6595,8 +6375,14 @@ const useChess = props => {
6595
6375
  return move;
6596
6376
  };
6597
6377
 
6598
- const onPromote = promotion => {
6599
- return onMove(lastMove[0], lastMove[1], promotion);
6378
+ const onPromote = async promotion => {
6379
+ const move = onMove(lastMove[0], lastMove[1], promotion);
6380
+
6381
+ if (typeof props.onMove === 'function') {
6382
+ await props.onMove(chess$1);
6383
+ }
6384
+
6385
+ return move;
6600
6386
  };
6601
6387
 
6602
6388
  return {
@@ -6605,6 +6391,7 @@ const useChess = props => {
6605
6391
  turnColor,
6606
6392
  lastMove,
6607
6393
  orientation,
6394
+ promotion,
6608
6395
  onMove,
6609
6396
  onPromote
6610
6397
  };
@@ -6668,7 +6455,61 @@ const Promote = ({
6668
6455
  })));
6669
6456
  };
6670
6457
 
6671
- const Chessboard = props => {
6458
+ const cgProps = props => {
6459
+ const cgProps = {};
6460
+
6461
+ if (props.viewOnly) {
6462
+ cgProps.draggable = false;
6463
+ cgProps.movable = {
6464
+ free: false
6465
+ };
6466
+ cgProps.drawable = {
6467
+ enabled: false
6468
+ };
6469
+ }
6470
+
6471
+ if (props.readOnly) {
6472
+ cgProps.draggable = false;
6473
+ cgProps.movable = {
6474
+ free: false
6475
+ };
6476
+ cgProps.drawable = {
6477
+ enabled: false
6478
+ };
6479
+ cgProps.coordinates = false;
6480
+ } // normalize orientation for Chessground
6481
+
6482
+
6483
+ if (props.orientation) {
6484
+ cgProps.orientation = props.orientation;
6485
+
6486
+ if (cgProps.orientation === 'w') {
6487
+ cgProps.orientation = 'white';
6488
+ }
6489
+
6490
+ if (cgProps.orientation === 'b') {
6491
+ cgProps.orientation = 'black';
6492
+ }
6493
+ }
6494
+
6495
+ if (props.options && props.options.shapes === false) {
6496
+ cgProps.drawable = {
6497
+ enabled: false
6498
+ };
6499
+ }
6500
+
6501
+ if (props.reply && props.reply.from && props.reply.to) {
6502
+ cgProps.onMove = () => {};
6503
+ }
6504
+
6505
+ if (props.shapes) {
6506
+ cgProps.shapes = props.shapes;
6507
+ }
6508
+
6509
+ return cgProps;
6510
+ };
6511
+
6512
+ const Chessboard = (props, ref) => {
6672
6513
  const {
6673
6514
  theme
6674
6515
  } = useChessground();
@@ -6683,19 +6524,21 @@ const Chessboard = props => {
6683
6524
  turnColor,
6684
6525
  lastMove,
6685
6526
  orientation,
6527
+ promotion,
6686
6528
  onMove,
6687
6529
  onPromote
6688
6530
  } = useChess(props);
6689
6531
 
6690
- const handleMove = (from, to) => {
6691
- const move = onMove(from, to);
6532
+ const handleMove = async (from, to) => {
6533
+ const move = onMove(from, to, promotion);
6692
6534
 
6693
6535
  if (!move) {
6694
6536
  show();
6695
- }
6537
+ } // pass the chess object to callback function
6538
+
6696
6539
 
6697
6540
  if (typeof props.onMove === 'function') {
6698
- props.onMove(from, to);
6541
+ await props.onMove(chess);
6699
6542
  }
6700
6543
 
6701
6544
  if (theme.playSounds) {
@@ -6703,31 +6546,15 @@ const Chessboard = props => {
6703
6546
  }
6704
6547
  };
6705
6548
 
6706
- const cgProps = {};
6707
-
6708
- if (props.viewOnly) {
6709
- cgProps.draggable = false;
6710
- cgProps.movable = {
6711
- free: false
6712
- };
6713
- } // normalize orientation for Chessground
6714
-
6715
-
6716
- if (props.orientation) {
6717
- cgProps.orientation = props.orientation;
6718
-
6719
- if (cgProps.orientation === 'w') {
6720
- cgProps.orientation = 'white';
6721
- }
6722
-
6723
- if (cgProps.orientation === 'b') {
6724
- cgProps.orientation = 'black';
6725
- }
6549
+ if (props.reply && props.reply.from && props.reply.to) {
6550
+ const cg = ref.current.board;
6551
+ cg.move(props.reply.from, props.reply.to);
6726
6552
  }
6727
6553
 
6728
6554
  return /*#__PURE__*/React.createElement("div", {
6729
6555
  className: mergeClassNames('chessground', theme.highlight && 'highlight', theme.board, theme.pieces)
6730
- }, /*#__PURE__*/React.createElement(Chessground, _extends({
6556
+ }, /*#__PURE__*/React.createElement(Chessground$1, _extends({
6557
+ ref: ref,
6731
6558
  coordinates: theme.coordinates,
6732
6559
  onMove: handleMove,
6733
6560
  fen: fen,
@@ -6735,7 +6562,7 @@ const Chessboard = props => {
6735
6562
  lastMove: lastMove,
6736
6563
  orientation: orientation,
6737
6564
  movable: toDests(chess)
6738
- }, cgProps)), /*#__PURE__*/React.createElement(Promote, {
6565
+ }, cgProps(props))), /*#__PURE__*/React.createElement(Promote, {
6739
6566
  isOpen: isOpen,
6740
6567
  hide: hide,
6741
6568
  color: turnColor,
@@ -6743,6 +6570,8 @@ const Chessboard = props => {
6743
6570
  }));
6744
6571
  };
6745
6572
 
6573
+ var Chessboard$1 = /*#__PURE__*/forwardRef(Chessboard);
6574
+
6746
6575
  const getOrientation = props => {
6747
6576
  try {
6748
6577
  if (props.orientation) {
@@ -6772,9 +6601,10 @@ const useOrientation = props => {
6772
6601
  return [orientation, flip];
6773
6602
  };
6774
6603
 
6775
- const NextChessground = props => {
6604
+ const NextChessground = (props, ref) => {
6776
6605
  const [theme, setTheme] = useState(themable());
6777
6606
  const [orientation, flip] = useOrientation(props);
6607
+ const showSettings = useMemo(() => !(props.readOnly === true), []);
6778
6608
  return /*#__PURE__*/React.createElement(ThemeContext.Provider, {
6779
6609
  value: {
6780
6610
  theme,
@@ -6782,15 +6612,18 @@ const NextChessground = props => {
6782
6612
  }
6783
6613
  }, /*#__PURE__*/React.createElement("div", {
6784
6614
  className: "next-chessground"
6785
- }, /*#__PURE__*/React.createElement(Chessboard, _extends({}, props, {
6615
+ }, /*#__PURE__*/React.createElement(Chessboard$1, _extends({}, props, {
6616
+ ref: ref,
6786
6617
  orientation: orientation
6787
- })), /*#__PURE__*/React.createElement("div", {
6618
+ })), showSettings && /*#__PURE__*/React.createElement("div", {
6788
6619
  className: "text-gray-400 flex flex-row-reverse gap-2 py-1.5"
6789
6620
  }, /*#__PURE__*/React.createElement(Settings, null), /*#__PURE__*/React.createElement(Flip, {
6790
6621
  onClick: flip
6791
6622
  }))));
6792
6623
  };
6793
6624
 
6625
+ var NextChessground$1 = /*#__PURE__*/forwardRef(NextChessground);
6626
+
6794
6627
  function styleInject(css, ref) {
6795
6628
  if (ref === void 0) ref = {};
6796
6629
  var insertAt = ref.insertAt;
@@ -6844,5 +6677,5 @@ styleInject(css_248z$6);
6844
6677
  var css_248z$7 = ".flex {\n display: flex;\n}\n.flex-col {\n flex-direction: column;\n}\n.flex-row-reverse {\n flex-direction: row-reverse;\n}\n.grid {\n display: grid;\n}\n.grid-cols-2 {\n grid-template-columns: repeat(2, minmax(0, 1fr));\n}\n.gap-2 {\n gap: 0.5rem;\n}\n.gap-3 {\n gap: 0.75rem;\n}\n.w-full {\n width: 100%;\n}\n.items-center {\n align-items: center;\n}\n.justify-center {\n justify-content: center;\n}\n.py-1\\.5 {\n padding-top: 0.375rem;\n padding-bottom: 0.375rem;\n}\n.px-2 {\n padding-left: 0.25rem;\n padding-right: 0.25rem;\n}\n.cursor-pointer {\n cursor: pointer;\n}\n.cursor-resize {\n cursor: nesw-resize;\n}\n.outline-none,\n.outline-none:focus {\n outline: none;\n}\n.text-sm {\n font-size: 0.875rem;\n line-height: 1.25rem;\n}\n.text-gray-400 {\n color: rgba(156, 163, 175);\n}\n.text-gray-800 {\n color: rgba(31, 41, 55);\n}\n.bg-white {\n background-color: #fff;\n}\n.border {\n border-width: 1px;\n border-style: solid;\n}\n.border-gray-300 {\n border-color: rgba(209, 213, 219);\n}\n.rounded {\n border-radius: 0.25rem;\n}\n";
6845
6678
  styleInject(css_248z$7);
6846
6679
 
6847
- export default NextChessground;
6848
- export { NextChessground, useChess, useChessground };
6680
+ export default NextChessground$1;
6681
+ export { NextChessground$1 as NextChessground, fen, useChess, useChessground };