gigaboard 1.4.2 → 1.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{board-model-BMtkLQvL.d.cts → board-model-BIVxSCWC.d.cts} +73 -2
- package/dist/{board-model-BMtkLQvL.d.ts → board-model-BIVxSCWC.d.ts} +73 -2
- package/dist/{chunk-EJUGH25P.js → chunk-53XWDREK.js} +4 -3
- package/dist/chunk-53XWDREK.js.map +1 -0
- package/dist/{chunk-SO6AOEFF.js → chunk-6F3FZAG7.js} +116 -18
- package/dist/chunk-6F3FZAG7.js.map +1 -0
- package/dist/{chunk-UBD62NOI.cjs → chunk-FUP2LDMO.cjs} +121 -16
- package/dist/chunk-FUP2LDMO.cjs.map +1 -0
- package/dist/{chunk-D45G3J5E.cjs → chunk-N4WTPXFC.cjs} +4 -2
- package/dist/chunk-N4WTPXFC.cjs.map +1 -0
- package/dist/core.cjs +72 -44
- package/dist/core.d.cts +17 -12
- package/dist/core.d.ts +17 -12
- package/dist/core.js +1 -1
- package/dist/{gigachess-C08uAeFw.d.ts → gigachess-DN-ncmAU.d.ts} +1 -1
- package/dist/{gigachess-Dr5gCN68.d.cts → gigachess-XpNGPM2m.d.cts} +1 -1
- package/dist/index.cjs +911 -250
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +61 -8
- package/dist/index.d.ts +61 -8
- package/dist/index.js +818 -189
- package/dist/index.js.map +1 -1
- package/dist/server.cjs +11 -11
- package/dist/server.d.cts +2 -2
- package/dist/server.d.ts +2 -2
- package/dist/server.js +1 -1
- package/dist/{types-CcOgT5ov.d.ts → types-4W8ULiE2.d.ts} +1 -1
- package/dist/{types-DfqRXtbD.d.cts → types-Dox7oLof.d.cts} +1 -1
- package/package.json +2 -2
- package/dist/chunk-D45G3J5E.cjs.map +0 -1
- package/dist/chunk-EJUGH25P.js.map +0 -1
- package/dist/chunk-SO6AOEFF.js.map +0 -1
- package/dist/chunk-UBD62NOI.cjs.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
var
|
|
3
|
+
var chunkFUP2LDMO_cjs = require('./chunk-FUP2LDMO.cjs');
|
|
4
|
+
var chunkN4WTPXFC_cjs = require('./chunk-N4WTPXFC.cjs');
|
|
5
5
|
require('./chunk-G6ZFOJZR.cjs');
|
|
6
6
|
require('./chunk-AYVQCHSG.cjs');
|
|
7
7
|
require('./chunk-FNRS6YJI.cjs');
|
|
@@ -9,6 +9,64 @@ var react = require('react');
|
|
|
9
9
|
var jsxRuntime = require('react/jsx-runtime');
|
|
10
10
|
|
|
11
11
|
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
12
|
+
var FILE_LETTERS = ["a", "b", "c", "d", "e", "f", "g", "h"];
|
|
13
|
+
function Coordinates({ orientation, ranksPosition = "left" }) {
|
|
14
|
+
const ranksOnRight = ranksPosition === "right";
|
|
15
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
16
|
+
"div",
|
|
17
|
+
{
|
|
18
|
+
"aria-hidden": "true",
|
|
19
|
+
style: {
|
|
20
|
+
position: "absolute",
|
|
21
|
+
inset: 0,
|
|
22
|
+
pointerEvents: "none",
|
|
23
|
+
fontSize: "min(1.6vmin, 11px)",
|
|
24
|
+
fontWeight: 600,
|
|
25
|
+
fontFamily: "system-ui, -apple-system, sans-serif"
|
|
26
|
+
},
|
|
27
|
+
children: [
|
|
28
|
+
FILE_LETTERS.map((letter, idx) => {
|
|
29
|
+
const col = orientation === "white" ? idx : 7 - idx;
|
|
30
|
+
const bottomRank = orientation === "white" ? 0 : 7;
|
|
31
|
+
const isLightSquare = (col + bottomRank) % 2 === 1;
|
|
32
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
33
|
+
"span",
|
|
34
|
+
{
|
|
35
|
+
style: {
|
|
36
|
+
position: "absolute",
|
|
37
|
+
left: `${col * 12.5 + 10}%`,
|
|
38
|
+
bottom: "1%",
|
|
39
|
+
color: `var(${isLightSquare ? chunkN4WTPXFC_cjs.CSS_VARS.COORDINATE_LIGHT : chunkN4WTPXFC_cjs.CSS_VARS.COORDINATE_DARK})`
|
|
40
|
+
},
|
|
41
|
+
children: letter
|
|
42
|
+
},
|
|
43
|
+
`file-${letter}`
|
|
44
|
+
);
|
|
45
|
+
}),
|
|
46
|
+
FILE_LETTERS.map((_, idx) => {
|
|
47
|
+
const rank = idx;
|
|
48
|
+
const row = orientation === "white" ? 7 - rank : rank;
|
|
49
|
+
const edgeFile = ranksOnRight ? orientation === "white" ? 7 : 0 : orientation === "white" ? 0 : 7;
|
|
50
|
+
const isLightSquare = (edgeFile + rank) % 2 === 1;
|
|
51
|
+
const sideStyle = ranksOnRight ? { right: "1%" } : { left: "1%" };
|
|
52
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
53
|
+
"span",
|
|
54
|
+
{
|
|
55
|
+
style: {
|
|
56
|
+
position: "absolute",
|
|
57
|
+
top: `${row * 12.5 + 1}%`,
|
|
58
|
+
...sideStyle,
|
|
59
|
+
color: `var(${isLightSquare ? chunkN4WTPXFC_cjs.CSS_VARS.COORDINATE_LIGHT : chunkN4WTPXFC_cjs.CSS_VARS.COORDINATE_DARK})`
|
|
60
|
+
},
|
|
61
|
+
children: rank + 1
|
|
62
|
+
},
|
|
63
|
+
`rank-${rank}`
|
|
64
|
+
);
|
|
65
|
+
})
|
|
66
|
+
]
|
|
67
|
+
}
|
|
68
|
+
);
|
|
69
|
+
}
|
|
12
70
|
function useBoardSnapshot(model) {
|
|
13
71
|
return react.useSyncExternalStore(model.subscribe, model.getSnapshot, model.getSnapshot);
|
|
14
72
|
}
|
|
@@ -22,12 +80,738 @@ function useSquareCell(model, index) {
|
|
|
22
80
|
},
|
|
23
81
|
[model, index]
|
|
24
82
|
);
|
|
25
|
-
const getSnapshot = react.useCallback(() => {
|
|
26
|
-
if (!model) return 0;
|
|
27
|
-
const snap = model.getSnapshot();
|
|
28
|
-
return snap.board[index] ?? 0;
|
|
29
|
-
}, [model, index]);
|
|
30
|
-
return react.useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
83
|
+
const getSnapshot = react.useCallback(() => {
|
|
84
|
+
if (!model) return 0;
|
|
85
|
+
const snap = model.getSnapshot();
|
|
86
|
+
return snap.board[index] ?? 0;
|
|
87
|
+
}, [model, index]);
|
|
88
|
+
return react.useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
89
|
+
}
|
|
90
|
+
function gridCoord(index, orientation) {
|
|
91
|
+
const file = index & 7;
|
|
92
|
+
const rank = index >> 3;
|
|
93
|
+
const col = orientation === "white" ? file + 1 : 8 - file;
|
|
94
|
+
const row = orientation === "white" ? 8 - rank : rank + 1;
|
|
95
|
+
return { col, row };
|
|
96
|
+
}
|
|
97
|
+
function algebraicOf(index) {
|
|
98
|
+
const file = index & 7;
|
|
99
|
+
const rank = index >> 3;
|
|
100
|
+
return `${String.fromCharCode(97 + file)}${rank + 1}`;
|
|
101
|
+
}
|
|
102
|
+
var SLOT_BASE_STYLE = Object.freeze({
|
|
103
|
+
display: "flex",
|
|
104
|
+
alignItems: "center",
|
|
105
|
+
justifyContent: "center",
|
|
106
|
+
pointerEvents: "none",
|
|
107
|
+
containerType: "size"
|
|
108
|
+
});
|
|
109
|
+
function PieceSlotImpl({ index, model, orientation, pieces }) {
|
|
110
|
+
const cell = useSquareCell(model, index);
|
|
111
|
+
if (cell === 0) return null;
|
|
112
|
+
const { col, row } = gridCoord(index, orientation);
|
|
113
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
114
|
+
"div",
|
|
115
|
+
{
|
|
116
|
+
"data-piece-square": algebraicOf(index),
|
|
117
|
+
"data-piece-cell": cell,
|
|
118
|
+
style: {
|
|
119
|
+
...SLOT_BASE_STYLE,
|
|
120
|
+
gridColumnStart: col,
|
|
121
|
+
gridRowStart: row,
|
|
122
|
+
filter: `var(${cell <= 6 ? chunkN4WTPXFC_cjs.CSS_VARS.PIECE_FILTER_WHITE : chunkN4WTPXFC_cjs.CSS_VARS.PIECE_FILTER_BLACK}, none)`
|
|
123
|
+
},
|
|
124
|
+
children: pieces({ cell, square: index })
|
|
125
|
+
}
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
var PieceSlot = react.memo(PieceSlotImpl);
|
|
129
|
+
PieceSlot.displayName = "PieceSlot";
|
|
130
|
+
var CONTAINER_STYLE = Object.freeze({
|
|
131
|
+
position: "absolute",
|
|
132
|
+
inset: 0,
|
|
133
|
+
display: "grid",
|
|
134
|
+
gridTemplateColumns: "repeat(8, 1fr)",
|
|
135
|
+
gridTemplateRows: "repeat(8, 1fr)",
|
|
136
|
+
pointerEvents: "none"
|
|
137
|
+
});
|
|
138
|
+
var PieceLayer = react.memo(function PieceLayer2({
|
|
139
|
+
model,
|
|
140
|
+
orientation,
|
|
141
|
+
pieces
|
|
142
|
+
}) {
|
|
143
|
+
const slots = [];
|
|
144
|
+
for (let i = 0; i < 64; i++) {
|
|
145
|
+
slots.push(
|
|
146
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
147
|
+
PieceSlot,
|
|
148
|
+
{
|
|
149
|
+
index: i,
|
|
150
|
+
model,
|
|
151
|
+
orientation,
|
|
152
|
+
pieces
|
|
153
|
+
},
|
|
154
|
+
i
|
|
155
|
+
)
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { "aria-hidden": "true", style: CONTAINER_STYLE, children: slots });
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
// src/lib/geometry.ts
|
|
162
|
+
function getSquareAtPoint(container, clientX, clientY, orientation) {
|
|
163
|
+
const rect = container.getBoundingClientRect();
|
|
164
|
+
const relX = clientX - rect.left;
|
|
165
|
+
const relY = clientY - rect.top;
|
|
166
|
+
if (relX < 0 || relY < 0 || relX >= rect.width || relY >= rect.height) return null;
|
|
167
|
+
const col = Math.floor(relX / rect.width * 8);
|
|
168
|
+
const row = Math.floor(relY / rect.height * 8);
|
|
169
|
+
const file = orientation === "white" ? col : 7 - col;
|
|
170
|
+
const rank = orientation === "white" ? 7 - row : row;
|
|
171
|
+
return rank * 8 + file;
|
|
172
|
+
}
|
|
173
|
+
function getPointAtSquareCentre(container, square, orientation) {
|
|
174
|
+
const rect = container.getBoundingClientRect();
|
|
175
|
+
const sqW = rect.width / 8;
|
|
176
|
+
const sqH = rect.height / 8;
|
|
177
|
+
const file = square & 7;
|
|
178
|
+
const rank = square >> 3;
|
|
179
|
+
const col = orientation === "white" ? file : 7 - file;
|
|
180
|
+
const row = orientation === "white" ? 7 - rank : rank;
|
|
181
|
+
return {
|
|
182
|
+
x: rect.left + sqW * col + sqW / 2,
|
|
183
|
+
y: rect.top + sqH * row + sqH / 2
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
function algebraicOf2(square) {
|
|
187
|
+
const file = square & 7;
|
|
188
|
+
const rank = square >> 3;
|
|
189
|
+
return `${String.fromCharCode(97 + file)}${rank + 1}`;
|
|
190
|
+
}
|
|
191
|
+
function squareOf(algebraic) {
|
|
192
|
+
if (algebraic.length !== 2) return null;
|
|
193
|
+
const file = algebraic.charCodeAt(0) - 97;
|
|
194
|
+
const rank = algebraic.charCodeAt(1) - 49;
|
|
195
|
+
if (file < 0 || file > 7 || rank < 0 || rank > 7) return null;
|
|
196
|
+
return rank << 3 | file;
|
|
197
|
+
}
|
|
198
|
+
var PIECE_CHARS = ["", "P", "N", "B", "R", "Q", "K", "p", "n", "b", "r", "q", "k"];
|
|
199
|
+
function formatFenPlacement(board) {
|
|
200
|
+
const rows = [];
|
|
201
|
+
for (let r = 7; r >= 0; r--) {
|
|
202
|
+
let empty = 0;
|
|
203
|
+
let row = "";
|
|
204
|
+
for (let f = 0; f < 8; f++) {
|
|
205
|
+
const cell = board[r * 8 + f] ?? 0;
|
|
206
|
+
if (cell === 0) {
|
|
207
|
+
empty++;
|
|
208
|
+
} else {
|
|
209
|
+
if (empty > 0) {
|
|
210
|
+
row += String(empty);
|
|
211
|
+
empty = 0;
|
|
212
|
+
}
|
|
213
|
+
row += PIECE_CHARS[cell] ?? "";
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
if (empty > 0) {
|
|
217
|
+
row += String(empty);
|
|
218
|
+
}
|
|
219
|
+
rows.push(row);
|
|
220
|
+
}
|
|
221
|
+
return rows.join("/");
|
|
222
|
+
}
|
|
223
|
+
function updateFenPlacement(originalFen, newPlacement) {
|
|
224
|
+
const tokens = originalFen.trim().split(/\s+/);
|
|
225
|
+
if (tokens.length <= 1) {
|
|
226
|
+
return newPlacement;
|
|
227
|
+
}
|
|
228
|
+
tokens[0] = newPlacement;
|
|
229
|
+
return tokens.join(" ");
|
|
230
|
+
}
|
|
231
|
+
function pieceNameFromCell(cell) {
|
|
232
|
+
if (cell === 0) return "empty";
|
|
233
|
+
const color = cell > 6 ? "black" : "white";
|
|
234
|
+
const type = (cell - 1) % 6;
|
|
235
|
+
const names = ["pawn", "knight", "bishop", "rook", "queen", "king"];
|
|
236
|
+
return `${color} ${names[type] ?? "piece"}`;
|
|
237
|
+
}
|
|
238
|
+
function defaultSquareLabel(square, cell) {
|
|
239
|
+
const sq = algebraicOf2(square);
|
|
240
|
+
if (cell === 0) {
|
|
241
|
+
return `${sq}, empty`;
|
|
242
|
+
}
|
|
243
|
+
return `${sq}, ${pieceNameFromCell(cell)}`;
|
|
244
|
+
}
|
|
245
|
+
function cellFromKey(key) {
|
|
246
|
+
switch (key) {
|
|
247
|
+
case "P":
|
|
248
|
+
return chunkFUP2LDMO_cjs.BOARD_CELL_WP;
|
|
249
|
+
case "N":
|
|
250
|
+
return chunkFUP2LDMO_cjs.BOARD_CELL_WN;
|
|
251
|
+
case "B":
|
|
252
|
+
return chunkFUP2LDMO_cjs.BOARD_CELL_WB;
|
|
253
|
+
case "R":
|
|
254
|
+
return chunkFUP2LDMO_cjs.BOARD_CELL_WR;
|
|
255
|
+
case "Q":
|
|
256
|
+
return chunkFUP2LDMO_cjs.BOARD_CELL_WQ;
|
|
257
|
+
case "K":
|
|
258
|
+
return chunkFUP2LDMO_cjs.BOARD_CELL_WK;
|
|
259
|
+
case "p":
|
|
260
|
+
return chunkFUP2LDMO_cjs.BOARD_CELL_BP;
|
|
261
|
+
case "n":
|
|
262
|
+
return chunkFUP2LDMO_cjs.BOARD_CELL_BN;
|
|
263
|
+
case "b":
|
|
264
|
+
return chunkFUP2LDMO_cjs.BOARD_CELL_BB;
|
|
265
|
+
case "r":
|
|
266
|
+
return chunkFUP2LDMO_cjs.BOARD_CELL_BR;
|
|
267
|
+
case "q":
|
|
268
|
+
return chunkFUP2LDMO_cjs.BOARD_CELL_BQ;
|
|
269
|
+
case "k":
|
|
270
|
+
return chunkFUP2LDMO_cjs.BOARD_CELL_BK;
|
|
271
|
+
default:
|
|
272
|
+
return 0;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
function cellFromPieceString(piece) {
|
|
276
|
+
if (!piece || piece === "erase") return 0;
|
|
277
|
+
if (piece.length === 2) {
|
|
278
|
+
const c0 = piece[0];
|
|
279
|
+
const c1 = piece[1];
|
|
280
|
+
if (c0 && c1) {
|
|
281
|
+
const color = c0.toLowerCase();
|
|
282
|
+
const type = c1.toUpperCase();
|
|
283
|
+
if (color === "w") return cellFromKey(type);
|
|
284
|
+
if (color === "b") return cellFromKey(type.toLowerCase());
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
return cellFromKey(piece);
|
|
288
|
+
}
|
|
289
|
+
function getOppositePieceString(piece) {
|
|
290
|
+
if (!piece || piece === "erase") return null;
|
|
291
|
+
if (piece.length === 2) {
|
|
292
|
+
const c0 = piece[0];
|
|
293
|
+
const c1 = piece[1];
|
|
294
|
+
if (c0 && c1) {
|
|
295
|
+
const color = c0 === "w" ? "b" : "w";
|
|
296
|
+
return `${color}${c1}`;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
return piece === piece.toUpperCase() ? piece.toLowerCase() : piece.toUpperCase();
|
|
300
|
+
}
|
|
301
|
+
function moveSquare(current, direction, orientation) {
|
|
302
|
+
const file = current & 7;
|
|
303
|
+
const rank = current >> 3;
|
|
304
|
+
const col = orientation === "white" ? file : 7 - file;
|
|
305
|
+
const row = orientation === "white" ? 7 - rank : rank;
|
|
306
|
+
let newCol = col;
|
|
307
|
+
let newRow = row;
|
|
308
|
+
switch (direction) {
|
|
309
|
+
case "up":
|
|
310
|
+
newRow = Math.max(0, row - 1);
|
|
311
|
+
break;
|
|
312
|
+
case "down":
|
|
313
|
+
newRow = Math.min(7, row + 1);
|
|
314
|
+
break;
|
|
315
|
+
case "left":
|
|
316
|
+
newCol = Math.max(0, col - 1);
|
|
317
|
+
break;
|
|
318
|
+
case "right":
|
|
319
|
+
newCol = Math.min(7, col + 1);
|
|
320
|
+
break;
|
|
321
|
+
}
|
|
322
|
+
const newFile = orientation === "white" ? newCol : 7 - newCol;
|
|
323
|
+
const newRank = orientation === "white" ? 7 - newRow : newRow;
|
|
324
|
+
return newRank * 8 + newFile & 63;
|
|
325
|
+
}
|
|
326
|
+
function rankEndSquare(current, which, orientation) {
|
|
327
|
+
const rank = current >> 3;
|
|
328
|
+
if (orientation === "white") {
|
|
329
|
+
return rank << 3 | (which === "home" ? 0 : 7);
|
|
330
|
+
}
|
|
331
|
+
return rank << 3 | (which === "home" ? 7 : 0);
|
|
332
|
+
}
|
|
333
|
+
function BoardEditor({
|
|
334
|
+
fen = "8/8/8/8/8/8/8/8 w - - 0 1",
|
|
335
|
+
onChange,
|
|
336
|
+
onPieceChange,
|
|
337
|
+
selectedPiece,
|
|
338
|
+
onSelectPiece,
|
|
339
|
+
orientation = "white",
|
|
340
|
+
theme = chunkN4WTPXFC_cjs.defaultTheme,
|
|
341
|
+
pieces = chunkN4WTPXFC_cjs.defaultPieces,
|
|
342
|
+
showCoordinates = false,
|
|
343
|
+
style,
|
|
344
|
+
className,
|
|
345
|
+
ariaLabel = "Board editor",
|
|
346
|
+
onAnnounce,
|
|
347
|
+
getSquareAriaLabel,
|
|
348
|
+
focusedSquare: propFocusedSquare,
|
|
349
|
+
onSquareFocus,
|
|
350
|
+
id,
|
|
351
|
+
onClear,
|
|
352
|
+
onSetStartingPosition,
|
|
353
|
+
onToggleSideToMove,
|
|
354
|
+
onFocus,
|
|
355
|
+
onBlur
|
|
356
|
+
}) {
|
|
357
|
+
const containerRef = react.useRef(null);
|
|
358
|
+
const liveRegionRef = react.useRef(null);
|
|
359
|
+
const liveCounter = react.useRef(0);
|
|
360
|
+
const [board, setBoard] = react.useState(() => {
|
|
361
|
+
try {
|
|
362
|
+
return chunkN4WTPXFC_cjs.parseFenPlacement(fen);
|
|
363
|
+
} catch {
|
|
364
|
+
return new Uint8Array(64);
|
|
365
|
+
}
|
|
366
|
+
});
|
|
367
|
+
const [internalFocusedSquare, setInternalFocusedSquare] = react.useState(
|
|
368
|
+
() => orientation === "white" ? 28 : 36
|
|
369
|
+
// e4 or e5
|
|
370
|
+
);
|
|
371
|
+
const focusedSquare = propFocusedSquare ?? internalFocusedSquare;
|
|
372
|
+
const setFocusedSquare = setInternalFocusedSquare;
|
|
373
|
+
const [hasKeyboardFocus, setHasKeyboardFocus] = react.useState(false);
|
|
374
|
+
const [dragging, setDragging] = react.useState(null);
|
|
375
|
+
react.useEffect(() => {
|
|
376
|
+
try {
|
|
377
|
+
const nextBoard = chunkN4WTPXFC_cjs.parseFenPlacement(fen);
|
|
378
|
+
setBoard(nextBoard);
|
|
379
|
+
} catch {
|
|
380
|
+
}
|
|
381
|
+
}, [fen]);
|
|
382
|
+
const announce = react.useCallback(
|
|
383
|
+
(message) => {
|
|
384
|
+
onAnnounce?.(message);
|
|
385
|
+
const region = liveRegionRef.current;
|
|
386
|
+
if (region) {
|
|
387
|
+
liveCounter.current++;
|
|
388
|
+
region.setAttribute("data-live-id", String(liveCounter.current));
|
|
389
|
+
region.textContent = "";
|
|
390
|
+
void region.offsetHeight;
|
|
391
|
+
region.textContent = message;
|
|
392
|
+
}
|
|
393
|
+
},
|
|
394
|
+
[onAnnounce]
|
|
395
|
+
);
|
|
396
|
+
const getSquareDescription = react.useCallback(
|
|
397
|
+
(square, cell) => {
|
|
398
|
+
const sq = algebraicOf2(square);
|
|
399
|
+
if (getSquareAriaLabel) {
|
|
400
|
+
return getSquareAriaLabel(square, cell, sq);
|
|
401
|
+
}
|
|
402
|
+
return defaultSquareLabel(square, cell);
|
|
403
|
+
},
|
|
404
|
+
[getSquareAriaLabel]
|
|
405
|
+
);
|
|
406
|
+
const announceSquare = react.useCallback(
|
|
407
|
+
(square) => {
|
|
408
|
+
const cell = board[square] ?? 0;
|
|
409
|
+
const desc = getSquareDescription(square, cell);
|
|
410
|
+
announce(desc);
|
|
411
|
+
onSquareFocus?.(square, cell, algebraicOf2(square));
|
|
412
|
+
},
|
|
413
|
+
[announce, board, getSquareDescription, onSquareFocus]
|
|
414
|
+
);
|
|
415
|
+
const commitBoard = react.useCallback(
|
|
416
|
+
(nextBoard) => {
|
|
417
|
+
setBoard(nextBoard);
|
|
418
|
+
const newPlacement = formatFenPlacement(nextBoard);
|
|
419
|
+
const updatedFen = updateFenPlacement(fen, newPlacement);
|
|
420
|
+
onChange?.(updatedFen);
|
|
421
|
+
},
|
|
422
|
+
[fen, onChange]
|
|
423
|
+
);
|
|
424
|
+
const placePieceAt = react.useCallback(
|
|
425
|
+
(square, cellOrCode) => {
|
|
426
|
+
const targetCell = typeof cellOrCode === "string" ? cellFromPieceString(cellOrCode) : cellOrCode;
|
|
427
|
+
const currentCell = board[square] ?? 0;
|
|
428
|
+
const nextBoard = new Uint8Array(board);
|
|
429
|
+
if (targetCell !== 0 && currentCell === targetCell) {
|
|
430
|
+
nextBoard[square] = 0;
|
|
431
|
+
commitBoard(nextBoard);
|
|
432
|
+
onPieceChange?.(square, 0, algebraicOf2(square));
|
|
433
|
+
announce(`Piece removed from ${algebraicOf2(square)}`);
|
|
434
|
+
} else if (targetCell !== 0) {
|
|
435
|
+
nextBoard[square] = targetCell;
|
|
436
|
+
commitBoard(nextBoard);
|
|
437
|
+
onPieceChange?.(square, targetCell, algebraicOf2(square));
|
|
438
|
+
const name = pieceNameFromCell(targetCell);
|
|
439
|
+
announce(`${name} placed on ${algebraicOf2(square)}`);
|
|
440
|
+
const char = PIECE_CHARS[targetCell] ?? "";
|
|
441
|
+
const code = targetCell <= 6 ? `w${char}` : `b${char.toUpperCase()}`;
|
|
442
|
+
onSelectPiece?.(code);
|
|
443
|
+
} else {
|
|
444
|
+
nextBoard[square] = 0;
|
|
445
|
+
commitBoard(nextBoard);
|
|
446
|
+
onPieceChange?.(square, 0, algebraicOf2(square));
|
|
447
|
+
announce(`Piece removed from ${algebraicOf2(square)}`);
|
|
448
|
+
}
|
|
449
|
+
},
|
|
450
|
+
[announce, board, commitBoard, onPieceChange, onSelectPiece]
|
|
451
|
+
);
|
|
452
|
+
const removePieceAt = react.useCallback(
|
|
453
|
+
(square) => {
|
|
454
|
+
const current = board[square] ?? 0;
|
|
455
|
+
if (current === 0) {
|
|
456
|
+
announce(`${algebraicOf2(square)} is empty`);
|
|
457
|
+
return;
|
|
458
|
+
}
|
|
459
|
+
const nextBoard = new Uint8Array(board);
|
|
460
|
+
nextBoard[square] = 0;
|
|
461
|
+
commitBoard(nextBoard);
|
|
462
|
+
onPieceChange?.(square, 0, algebraicOf2(square));
|
|
463
|
+
announce(`Piece removed from ${algebraicOf2(square)}`);
|
|
464
|
+
},
|
|
465
|
+
[announce, board, commitBoard, onPieceChange]
|
|
466
|
+
);
|
|
467
|
+
const handleKeyDown = react.useCallback(
|
|
468
|
+
(e) => {
|
|
469
|
+
if (e.altKey || e.ctrlKey || e.metaKey) return;
|
|
470
|
+
if (e.key.startsWith("Arrow")) {
|
|
471
|
+
if (e.shiftKey) return;
|
|
472
|
+
e.preventDefault();
|
|
473
|
+
const dir = e.key === "ArrowUp" ? "up" : e.key === "ArrowDown" ? "down" : e.key === "ArrowLeft" ? "left" : "right";
|
|
474
|
+
const next = moveSquare(focusedSquare, dir, orientation);
|
|
475
|
+
setFocusedSquare(next);
|
|
476
|
+
announceSquare(next);
|
|
477
|
+
return;
|
|
478
|
+
}
|
|
479
|
+
if (e.key === "Home" || e.key === "End") {
|
|
480
|
+
e.preventDefault();
|
|
481
|
+
const next = rankEndSquare(focusedSquare, e.key === "Home" ? "home" : "end", orientation);
|
|
482
|
+
setFocusedSquare(next);
|
|
483
|
+
announceSquare(next);
|
|
484
|
+
return;
|
|
485
|
+
}
|
|
486
|
+
if (e.key === "Backspace" || e.key === "Delete" || e.key === "x" || e.key === "X") {
|
|
487
|
+
e.preventDefault();
|
|
488
|
+
removePieceAt(focusedSquare);
|
|
489
|
+
return;
|
|
490
|
+
}
|
|
491
|
+
if (e.key === "c" || e.key === "C") {
|
|
492
|
+
e.preventDefault();
|
|
493
|
+
if (onClear) {
|
|
494
|
+
onClear();
|
|
495
|
+
} else {
|
|
496
|
+
commitBoard(new Uint8Array(64));
|
|
497
|
+
announce("Board cleared");
|
|
498
|
+
}
|
|
499
|
+
return;
|
|
500
|
+
}
|
|
501
|
+
if (e.key === "s" || e.key === "S") {
|
|
502
|
+
e.preventDefault();
|
|
503
|
+
if (onSetStartingPosition) {
|
|
504
|
+
onSetStartingPosition();
|
|
505
|
+
} else {
|
|
506
|
+
commitBoard(chunkN4WTPXFC_cjs.parseFenPlacement(chunkN4WTPXFC_cjs.STARTING_FEN));
|
|
507
|
+
announce("Starting position");
|
|
508
|
+
}
|
|
509
|
+
return;
|
|
510
|
+
}
|
|
511
|
+
if (e.key === "t" || e.key === "T") {
|
|
512
|
+
e.preventDefault();
|
|
513
|
+
onToggleSideToMove?.();
|
|
514
|
+
return;
|
|
515
|
+
}
|
|
516
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
517
|
+
e.preventDefault();
|
|
518
|
+
if (selectedPiece) {
|
|
519
|
+
const piece = e.shiftKey ? getOppositePieceString(selectedPiece) : selectedPiece;
|
|
520
|
+
if (piece) placePieceAt(focusedSquare, piece);
|
|
521
|
+
}
|
|
522
|
+
return;
|
|
523
|
+
}
|
|
524
|
+
const pieceCell = cellFromKey(e.key);
|
|
525
|
+
if (pieceCell !== 0) {
|
|
526
|
+
e.preventDefault();
|
|
527
|
+
placePieceAt(focusedSquare, pieceCell);
|
|
528
|
+
}
|
|
529
|
+
},
|
|
530
|
+
[
|
|
531
|
+
announce,
|
|
532
|
+
announceSquare,
|
|
533
|
+
commitBoard,
|
|
534
|
+
focusedSquare,
|
|
535
|
+
onClear,
|
|
536
|
+
onSetStartingPosition,
|
|
537
|
+
onToggleSideToMove,
|
|
538
|
+
orientation,
|
|
539
|
+
placePieceAt,
|
|
540
|
+
removePieceAt,
|
|
541
|
+
selectedPiece
|
|
542
|
+
]
|
|
543
|
+
);
|
|
544
|
+
const handlePointerDown = (e) => {
|
|
545
|
+
if (e.button !== 0) return;
|
|
546
|
+
const container = containerRef.current;
|
|
547
|
+
if (!container) return;
|
|
548
|
+
const sq = getSquareAtPoint(container, e.clientX, e.clientY, orientation);
|
|
549
|
+
if (sq === null) return;
|
|
550
|
+
container.focus();
|
|
551
|
+
setFocusedSquare(sq);
|
|
552
|
+
onSquareFocus?.(sq, board[sq] ?? 0, algebraicOf2(sq));
|
|
553
|
+
const cell = board[sq] ?? 0;
|
|
554
|
+
if (cell === 0) {
|
|
555
|
+
if (selectedPiece) {
|
|
556
|
+
placePieceAt(sq, selectedPiece);
|
|
557
|
+
}
|
|
558
|
+
return;
|
|
559
|
+
}
|
|
560
|
+
e.currentTarget.setPointerCapture(e.pointerId);
|
|
561
|
+
setDragging({
|
|
562
|
+
origin: sq,
|
|
563
|
+
cell,
|
|
564
|
+
x: e.clientX,
|
|
565
|
+
y: e.clientY
|
|
566
|
+
});
|
|
567
|
+
};
|
|
568
|
+
const handlePointerMove = (e) => {
|
|
569
|
+
if (!dragging) return;
|
|
570
|
+
setDragging((prev) => prev ? { ...prev, x: e.clientX, y: e.clientY } : null);
|
|
571
|
+
};
|
|
572
|
+
const handlePointerUp = (e) => {
|
|
573
|
+
if (!dragging) return;
|
|
574
|
+
const container = containerRef.current;
|
|
575
|
+
const originSq = dragging.origin;
|
|
576
|
+
const movedCell = dragging.cell;
|
|
577
|
+
setDragging(null);
|
|
578
|
+
if (!container) return;
|
|
579
|
+
const targetSq = getSquareAtPoint(container, e.clientX, e.clientY, orientation);
|
|
580
|
+
if (targetSq === null) {
|
|
581
|
+
removePieceAt(originSq);
|
|
582
|
+
return;
|
|
583
|
+
}
|
|
584
|
+
if (targetSq === originSq) {
|
|
585
|
+
if (selectedPiece) {
|
|
586
|
+
placePieceAt(originSq, selectedPiece);
|
|
587
|
+
}
|
|
588
|
+
return;
|
|
589
|
+
}
|
|
590
|
+
const nextBoard = new Uint8Array(board);
|
|
591
|
+
nextBoard[originSq] = 0;
|
|
592
|
+
nextBoard[targetSq] = movedCell;
|
|
593
|
+
commitBoard(nextBoard);
|
|
594
|
+
announce(`${pieceNameFromCell(movedCell)} moved to ${algebraicOf2(targetSq)}`);
|
|
595
|
+
setFocusedSquare(targetSq);
|
|
596
|
+
};
|
|
597
|
+
const handleContextMenu = (e) => {
|
|
598
|
+
e.preventDefault();
|
|
599
|
+
const container = containerRef.current;
|
|
600
|
+
if (!container) return;
|
|
601
|
+
const sq = getSquareAtPoint(container, e.clientX, e.clientY, orientation);
|
|
602
|
+
if (sq === null) return;
|
|
603
|
+
setFocusedSquare(sq);
|
|
604
|
+
if (selectedPiece) {
|
|
605
|
+
const opp = getOppositePieceString(selectedPiece);
|
|
606
|
+
if (opp) placePieceAt(sq, opp);
|
|
607
|
+
}
|
|
608
|
+
};
|
|
609
|
+
const squareOrder = react.useMemo(() => {
|
|
610
|
+
const squares = [];
|
|
611
|
+
if (orientation === "white") {
|
|
612
|
+
for (let rank = 7; rank >= 0; rank--) {
|
|
613
|
+
for (let file = 0; file < 8; file++) {
|
|
614
|
+
squares.push(rank * 8 + file);
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
} else {
|
|
618
|
+
for (let rank = 0; rank < 8; rank++) {
|
|
619
|
+
for (let file = 7; file >= 0; file--) {
|
|
620
|
+
squares.push(rank * 8 + file);
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
return squares;
|
|
625
|
+
}, [orientation]);
|
|
626
|
+
const containerStyle = {
|
|
627
|
+
position: "relative",
|
|
628
|
+
aspectRatio: "1 / 1",
|
|
629
|
+
width: "100%",
|
|
630
|
+
touchAction: "none",
|
|
631
|
+
outline: hasKeyboardFocus ? "3px solid var(--gb-editor-focus, #d97706)" : "none",
|
|
632
|
+
outlineOffset: "2px",
|
|
633
|
+
borderRadius: "8px",
|
|
634
|
+
...theme,
|
|
635
|
+
...style
|
|
636
|
+
};
|
|
637
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
638
|
+
"div",
|
|
639
|
+
{
|
|
640
|
+
ref: containerRef,
|
|
641
|
+
id,
|
|
642
|
+
role: "application",
|
|
643
|
+
tabIndex: 0,
|
|
644
|
+
"aria-label": ariaLabel,
|
|
645
|
+
"aria-keyshortcuts": "ArrowUp ArrowDown ArrowLeft ArrowRight Enter Space Backspace Delete p P n N b B r R q Q k K c C s S t T",
|
|
646
|
+
onKeyDown: handleKeyDown,
|
|
647
|
+
onFocus: (e) => {
|
|
648
|
+
if (e.target === e.currentTarget) {
|
|
649
|
+
setHasKeyboardFocus(true);
|
|
650
|
+
announceSquare(focusedSquare);
|
|
651
|
+
}
|
|
652
|
+
onFocus?.(e);
|
|
653
|
+
},
|
|
654
|
+
onBlur: (e) => {
|
|
655
|
+
if (e.target === e.currentTarget) {
|
|
656
|
+
setHasKeyboardFocus(false);
|
|
657
|
+
}
|
|
658
|
+
onBlur?.(e);
|
|
659
|
+
},
|
|
660
|
+
onPointerDown: handlePointerDown,
|
|
661
|
+
onPointerMove: handlePointerMove,
|
|
662
|
+
onPointerUp: handlePointerUp,
|
|
663
|
+
onPointerCancel: () => setDragging(null),
|
|
664
|
+
onContextMenu: handleContextMenu,
|
|
665
|
+
className,
|
|
666
|
+
style: containerStyle,
|
|
667
|
+
"data-gb-editor": "true",
|
|
668
|
+
"data-gb-orientation": orientation,
|
|
669
|
+
children: [
|
|
670
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
671
|
+
"div",
|
|
672
|
+
{
|
|
673
|
+
"aria-hidden": "true",
|
|
674
|
+
style: {
|
|
675
|
+
position: "absolute",
|
|
676
|
+
inset: 0,
|
|
677
|
+
display: "grid",
|
|
678
|
+
gridTemplateColumns: "repeat(8, 1fr)",
|
|
679
|
+
gridTemplateRows: "repeat(8, 1fr)",
|
|
680
|
+
pointerEvents: "none"
|
|
681
|
+
},
|
|
682
|
+
children: squareOrder.map((sq) => {
|
|
683
|
+
const file = sq & 7;
|
|
684
|
+
const rank = sq >> 3;
|
|
685
|
+
const isLight = (file + rank & 1) !== 0;
|
|
686
|
+
const isFocused = hasKeyboardFocus && focusedSquare === sq;
|
|
687
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
688
|
+
"div",
|
|
689
|
+
{
|
|
690
|
+
"data-square": algebraicOf2(sq),
|
|
691
|
+
style: {
|
|
692
|
+
position: "relative",
|
|
693
|
+
backgroundColor: `var(${isLight ? chunkN4WTPXFC_cjs.CSS_VARS.SQ_LIGHT : chunkN4WTPXFC_cjs.CSS_VARS.SQ_DARK})`,
|
|
694
|
+
backgroundImage: `var(${isLight ? chunkN4WTPXFC_cjs.CSS_VARS.SQ_LIGHT_IMAGE : chunkN4WTPXFC_cjs.CSS_VARS.SQ_DARK_IMAGE},none)`,
|
|
695
|
+
backgroundSize: `var(${chunkN4WTPXFC_cjs.CSS_VARS.SQ_IMAGE_SIZE},cover)`,
|
|
696
|
+
boxShadow: isFocused ? "inset 0 0 0 3px rgba(255, 206, 76, 0.95)" : void 0,
|
|
697
|
+
userSelect: "none"
|
|
698
|
+
}
|
|
699
|
+
},
|
|
700
|
+
sq
|
|
701
|
+
);
|
|
702
|
+
})
|
|
703
|
+
}
|
|
704
|
+
),
|
|
705
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
706
|
+
"div",
|
|
707
|
+
{
|
|
708
|
+
"aria-hidden": "true",
|
|
709
|
+
style: {
|
|
710
|
+
position: "absolute",
|
|
711
|
+
inset: 0,
|
|
712
|
+
display: "grid",
|
|
713
|
+
gridTemplateColumns: "repeat(8, 1fr)",
|
|
714
|
+
gridTemplateRows: "repeat(8, 1fr)",
|
|
715
|
+
pointerEvents: "none"
|
|
716
|
+
},
|
|
717
|
+
children: squareOrder.map((sq) => {
|
|
718
|
+
const cell = board[sq] ?? 0;
|
|
719
|
+
if (cell === 0) return null;
|
|
720
|
+
const isOrigin = dragging?.origin === sq;
|
|
721
|
+
const { col, row } = gridCoord(sq, orientation);
|
|
722
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
723
|
+
"div",
|
|
724
|
+
{
|
|
725
|
+
"data-piece-square": algebraicOf2(sq),
|
|
726
|
+
style: {
|
|
727
|
+
...SLOT_BASE_STYLE,
|
|
728
|
+
gridColumnStart: col,
|
|
729
|
+
gridRowStart: row,
|
|
730
|
+
opacity: isOrigin ? 0.25 : 1,
|
|
731
|
+
filter: `var(${cell <= 6 ? chunkN4WTPXFC_cjs.CSS_VARS.PIECE_FILTER_WHITE : chunkN4WTPXFC_cjs.CSS_VARS.PIECE_FILTER_BLACK}, none)`,
|
|
732
|
+
pointerEvents: "none"
|
|
733
|
+
},
|
|
734
|
+
children: pieces({ cell, square: sq })
|
|
735
|
+
},
|
|
736
|
+
sq
|
|
737
|
+
);
|
|
738
|
+
})
|
|
739
|
+
}
|
|
740
|
+
),
|
|
741
|
+
hasKeyboardFocus && /* @__PURE__ */ jsxRuntime.jsx(
|
|
742
|
+
"div",
|
|
743
|
+
{
|
|
744
|
+
"aria-hidden": "true",
|
|
745
|
+
style: {
|
|
746
|
+
position: "absolute",
|
|
747
|
+
inset: 0,
|
|
748
|
+
display: "grid",
|
|
749
|
+
gridTemplateColumns: "repeat(8, 1fr)",
|
|
750
|
+
gridTemplateRows: "repeat(8, 1fr)",
|
|
751
|
+
pointerEvents: "none",
|
|
752
|
+
zIndex: 10
|
|
753
|
+
},
|
|
754
|
+
children: (() => {
|
|
755
|
+
const { col, row } = gridCoord(focusedSquare, orientation);
|
|
756
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
757
|
+
"div",
|
|
758
|
+
{
|
|
759
|
+
"data-gb-editor-focus-square": algebraicOf2(focusedSquare),
|
|
760
|
+
style: {
|
|
761
|
+
gridColumnStart: col,
|
|
762
|
+
gridRowStart: row,
|
|
763
|
+
outline: "3px solid var(--gb-editor-sq-focus, #f59e0b)",
|
|
764
|
+
outlineOffset: "-3px",
|
|
765
|
+
boxShadow: "inset 0 0 0 1.5px rgba(0, 0, 0, 0.75), 0 0 8px rgba(245, 158, 11, 0.7)",
|
|
766
|
+
borderRadius: "2px",
|
|
767
|
+
pointerEvents: "none"
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
);
|
|
771
|
+
})()
|
|
772
|
+
}
|
|
773
|
+
),
|
|
774
|
+
dragging && containerRef.current ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
775
|
+
"div",
|
|
776
|
+
{
|
|
777
|
+
"aria-hidden": "true",
|
|
778
|
+
style: {
|
|
779
|
+
position: "fixed",
|
|
780
|
+
left: dragging.x - 30,
|
|
781
|
+
top: dragging.y - 30,
|
|
782
|
+
width: 60,
|
|
783
|
+
height: 60,
|
|
784
|
+
pointerEvents: "none",
|
|
785
|
+
zIndex: 100,
|
|
786
|
+
filter: `var(${dragging.cell <= 6 ? chunkN4WTPXFC_cjs.CSS_VARS.PIECE_FILTER_WHITE : chunkN4WTPXFC_cjs.CSS_VARS.PIECE_FILTER_BLACK}, none)`
|
|
787
|
+
},
|
|
788
|
+
children: pieces({ cell: dragging.cell, square: dragging.origin })
|
|
789
|
+
}
|
|
790
|
+
) : null,
|
|
791
|
+
showCoordinates ? /* @__PURE__ */ jsxRuntime.jsx(Coordinates, { orientation }) : null,
|
|
792
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
793
|
+
"div",
|
|
794
|
+
{
|
|
795
|
+
ref: liveRegionRef,
|
|
796
|
+
role: "status",
|
|
797
|
+
"aria-live": "assertive",
|
|
798
|
+
"aria-atomic": "true",
|
|
799
|
+
style: {
|
|
800
|
+
position: "absolute",
|
|
801
|
+
width: 1,
|
|
802
|
+
height: 1,
|
|
803
|
+
padding: 0,
|
|
804
|
+
margin: -1,
|
|
805
|
+
overflow: "hidden",
|
|
806
|
+
clip: "rect(0, 0, 0, 0)",
|
|
807
|
+
whiteSpace: "nowrap",
|
|
808
|
+
border: 0
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
)
|
|
812
|
+
]
|
|
813
|
+
}
|
|
814
|
+
);
|
|
31
815
|
}
|
|
32
816
|
function squareCentrePct(index, orientation) {
|
|
33
817
|
const file = index & 7;
|
|
@@ -608,7 +1392,7 @@ function injectFocusRingStyles() {
|
|
|
608
1392
|
`;
|
|
609
1393
|
document.head.appendChild(style);
|
|
610
1394
|
}
|
|
611
|
-
function
|
|
1395
|
+
function algebraicOf3(index) {
|
|
612
1396
|
const file = index & 7;
|
|
613
1397
|
const rank = index >> 3;
|
|
614
1398
|
return `${String.fromCharCode(97 + file)}${rank + 1}`;
|
|
@@ -627,7 +1411,7 @@ function SquareImpl({
|
|
|
627
1411
|
const rank = index >> 3;
|
|
628
1412
|
const isLight = (file + rank) % 2 === 1;
|
|
629
1413
|
const cell = useSquareCell(model, index);
|
|
630
|
-
const label = getSquareAriaLabel ? getSquareAriaLabel(index, cell) :
|
|
1414
|
+
const label = getSquareAriaLabel ? getSquareAriaLabel(index, cell) : algebraicOf3(index);
|
|
631
1415
|
const internalRef = react.useRef(null);
|
|
632
1416
|
const lastReportedFocusRef = react.useRef(false);
|
|
633
1417
|
const setRef = react.useCallback(
|
|
@@ -670,7 +1454,7 @@ function SquareImpl({
|
|
|
670
1454
|
"aria-rowindex": rank + 1,
|
|
671
1455
|
"aria-colindex": file + 1,
|
|
672
1456
|
tabIndex: isFocused ? 0 : -1,
|
|
673
|
-
"data-square":
|
|
1457
|
+
"data-square": algebraicOf3(index),
|
|
674
1458
|
"data-gb-square": "",
|
|
675
1459
|
"data-light": isLight ? "true" : "false",
|
|
676
1460
|
onClick: handleClick,
|
|
@@ -680,10 +1464,10 @@ function SquareImpl({
|
|
|
680
1464
|
// `backgroundColor` (not the `background` shorthand) so the
|
|
681
1465
|
// CSS `background-image` set by `useSelectionController` (or pseudo-elements)
|
|
682
1466
|
// can layer on top without clobbering this base colour.
|
|
683
|
-
backgroundColor: `var(${isLight ?
|
|
684
|
-
backgroundImage: `var(${isLight ?
|
|
685
|
-
backgroundSize: `var(${
|
|
686
|
-
backgroundBlendMode: `var(${
|
|
1467
|
+
backgroundColor: `var(${isLight ? chunkN4WTPXFC_cjs.CSS_VARS.SQ_LIGHT : chunkN4WTPXFC_cjs.CSS_VARS.SQ_DARK})`,
|
|
1468
|
+
backgroundImage: `var(${isLight ? chunkN4WTPXFC_cjs.CSS_VARS.SQ_LIGHT_IMAGE : chunkN4WTPXFC_cjs.CSS_VARS.SQ_DARK_IMAGE},none)`,
|
|
1469
|
+
backgroundSize: `var(${chunkN4WTPXFC_cjs.CSS_VARS.SQ_IMAGE_SIZE},cover)`,
|
|
1470
|
+
backgroundBlendMode: `var(${chunkN4WTPXFC_cjs.CSS_VARS.SQ_BLEND_MODE},normal)`,
|
|
687
1471
|
// Cursor is managed by `useCursorController` via injected CSS so
|
|
688
1472
|
// it can flip between `pointer` / `grab` / `grabbing` without a
|
|
689
1473
|
// React re-render per hover.
|
|
@@ -801,71 +1585,13 @@ function CheckLayerInner({ model, orientation }) {
|
|
|
801
1585
|
top: `${y}%`,
|
|
802
1586
|
width: "12.5%",
|
|
803
1587
|
height: "12.5%",
|
|
804
|
-
background: `var(${
|
|
1588
|
+
background: `var(${chunkN4WTPXFC_cjs.CSS_VARS.CHECK})`,
|
|
805
1589
|
pointerEvents: "none",
|
|
806
1590
|
zIndex: 2
|
|
807
1591
|
}
|
|
808
1592
|
}
|
|
809
1593
|
);
|
|
810
1594
|
}
|
|
811
|
-
var FILE_LETTERS = ["a", "b", "c", "d", "e", "f", "g", "h"];
|
|
812
|
-
function Coordinates({ orientation, ranksPosition = "left" }) {
|
|
813
|
-
const ranksOnRight = ranksPosition === "right";
|
|
814
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
815
|
-
"div",
|
|
816
|
-
{
|
|
817
|
-
"aria-hidden": "true",
|
|
818
|
-
style: {
|
|
819
|
-
position: "absolute",
|
|
820
|
-
inset: 0,
|
|
821
|
-
pointerEvents: "none",
|
|
822
|
-
fontSize: "min(1.6vmin, 11px)",
|
|
823
|
-
fontWeight: 600,
|
|
824
|
-
fontFamily: "system-ui, -apple-system, sans-serif"
|
|
825
|
-
},
|
|
826
|
-
children: [
|
|
827
|
-
FILE_LETTERS.map((letter, idx) => {
|
|
828
|
-
const col = orientation === "white" ? idx : 7 - idx;
|
|
829
|
-
const bottomRank = orientation === "white" ? 0 : 7;
|
|
830
|
-
const isLightSquare = (col + bottomRank) % 2 === 1;
|
|
831
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
832
|
-
"span",
|
|
833
|
-
{
|
|
834
|
-
style: {
|
|
835
|
-
position: "absolute",
|
|
836
|
-
left: `${col * 12.5 + 10}%`,
|
|
837
|
-
bottom: "1%",
|
|
838
|
-
color: `var(${isLightSquare ? chunkD45G3J5E_cjs.CSS_VARS.COORDINATE_LIGHT : chunkD45G3J5E_cjs.CSS_VARS.COORDINATE_DARK})`
|
|
839
|
-
},
|
|
840
|
-
children: letter
|
|
841
|
-
},
|
|
842
|
-
`file-${letter}`
|
|
843
|
-
);
|
|
844
|
-
}),
|
|
845
|
-
FILE_LETTERS.map((_, idx) => {
|
|
846
|
-
const rank = idx;
|
|
847
|
-
const row = orientation === "white" ? 7 - rank : rank;
|
|
848
|
-
const edgeFile = ranksOnRight ? orientation === "white" ? 7 : 0 : orientation === "white" ? 0 : 7;
|
|
849
|
-
const isLightSquare = (edgeFile + rank) % 2 === 1;
|
|
850
|
-
const sideStyle = ranksOnRight ? { right: "1%" } : { left: "1%" };
|
|
851
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
852
|
-
"span",
|
|
853
|
-
{
|
|
854
|
-
style: {
|
|
855
|
-
position: "absolute",
|
|
856
|
-
top: `${row * 12.5 + 1}%`,
|
|
857
|
-
...sideStyle,
|
|
858
|
-
color: `var(${isLightSquare ? chunkD45G3J5E_cjs.CSS_VARS.COORDINATE_LIGHT : chunkD45G3J5E_cjs.CSS_VARS.COORDINATE_DARK})`
|
|
859
|
-
},
|
|
860
|
-
children: rank + 1
|
|
861
|
-
},
|
|
862
|
-
`rank-${rank}`
|
|
863
|
-
);
|
|
864
|
-
})
|
|
865
|
-
]
|
|
866
|
-
}
|
|
867
|
-
);
|
|
868
|
-
}
|
|
869
1595
|
var WRAPPER_STYLE = Object.freeze({
|
|
870
1596
|
position: "absolute",
|
|
871
1597
|
top: 0,
|
|
@@ -902,7 +1628,7 @@ var DragLayer = react.forwardRef(function DragLayer2({ pieces }, ref) {
|
|
|
902
1628
|
"data-drag-cell": cell,
|
|
903
1629
|
style: {
|
|
904
1630
|
...SLOT_STYLE,
|
|
905
|
-
filter: `var(${cell <= 6 ?
|
|
1631
|
+
filter: `var(${cell <= 6 ? chunkN4WTPXFC_cjs.CSS_VARS.PIECE_FILTER_WHITE : chunkN4WTPXFC_cjs.CSS_VARS.PIECE_FILTER_BLACK}, none)`
|
|
906
1632
|
},
|
|
907
1633
|
children: child
|
|
908
1634
|
},
|
|
@@ -1000,7 +1726,7 @@ function IllegalFlashLayer({ at, orientation }) {
|
|
|
1000
1726
|
top: `${y}%`,
|
|
1001
1727
|
width: "12.5%",
|
|
1002
1728
|
height: "12.5%",
|
|
1003
|
-
background:
|
|
1729
|
+
background: chunkN4WTPXFC_cjs.DEFAULT_ILLEGAL_FLASH_TINT,
|
|
1004
1730
|
opacity: 0,
|
|
1005
1731
|
pointerEvents: "none",
|
|
1006
1732
|
zIndex: 5
|
|
@@ -1008,7 +1734,7 @@ function IllegalFlashLayer({ at, orientation }) {
|
|
|
1008
1734
|
}
|
|
1009
1735
|
);
|
|
1010
1736
|
}
|
|
1011
|
-
function
|
|
1737
|
+
function algebraicOf4(index) {
|
|
1012
1738
|
const file = index & 7;
|
|
1013
1739
|
const rank = index >> 3;
|
|
1014
1740
|
return `${String.fromCharCode(97 + file)}${rank + 1}`;
|
|
@@ -1035,15 +1761,16 @@ function pieceName(cell) {
|
|
|
1035
1761
|
}
|
|
1036
1762
|
}
|
|
1037
1763
|
function announcementFor(lastMove, board, wasCapture) {
|
|
1038
|
-
const { from, to, kind, promotion } =
|
|
1764
|
+
const { from, to, kind, promotion } = chunkFUP2LDMO_cjs.decodePackedMove(lastMove);
|
|
1765
|
+
if (kind === "pass") return "Passes.";
|
|
1039
1766
|
if (kind === "castle") {
|
|
1040
1767
|
const isKingside = (to & 7) > (from & 7);
|
|
1041
1768
|
return isKingside ? "Castles kingside." : "Castles queenside.";
|
|
1042
1769
|
}
|
|
1043
1770
|
const landed = board[to] ?? 0;
|
|
1044
1771
|
const name = pieceName(landed);
|
|
1045
|
-
const fromSq =
|
|
1046
|
-
const toSq =
|
|
1772
|
+
const fromSq = algebraicOf4(from);
|
|
1773
|
+
const toSq = algebraicOf4(to);
|
|
1047
1774
|
if (kind === "promotion" && promotion !== null) {
|
|
1048
1775
|
const promoted = promotion === 1 ? "knight" : promotion === 2 ? "bishop" : promotion === 3 ? "rook" : "queen";
|
|
1049
1776
|
const action = wasCapture ? "captures and promotes" : "promotes";
|
|
@@ -1092,76 +1819,6 @@ function LiveRegion({ model }) {
|
|
|
1092
1819
|
}
|
|
1093
1820
|
);
|
|
1094
1821
|
}
|
|
1095
|
-
function gridCoord(index, orientation) {
|
|
1096
|
-
const file = index & 7;
|
|
1097
|
-
const rank = index >> 3;
|
|
1098
|
-
const col = orientation === "white" ? file + 1 : 8 - file;
|
|
1099
|
-
const row = orientation === "white" ? 8 - rank : rank + 1;
|
|
1100
|
-
return { col, row };
|
|
1101
|
-
}
|
|
1102
|
-
function algebraicOf3(index) {
|
|
1103
|
-
const file = index & 7;
|
|
1104
|
-
const rank = index >> 3;
|
|
1105
|
-
return `${String.fromCharCode(97 + file)}${rank + 1}`;
|
|
1106
|
-
}
|
|
1107
|
-
var SLOT_BASE_STYLE = Object.freeze({
|
|
1108
|
-
display: "flex",
|
|
1109
|
-
alignItems: "center",
|
|
1110
|
-
justifyContent: "center",
|
|
1111
|
-
pointerEvents: "none",
|
|
1112
|
-
containerType: "size"
|
|
1113
|
-
});
|
|
1114
|
-
function PieceSlotImpl({ index, model, orientation, pieces }) {
|
|
1115
|
-
const cell = useSquareCell(model, index);
|
|
1116
|
-
if (cell === 0) return null;
|
|
1117
|
-
const { col, row } = gridCoord(index, orientation);
|
|
1118
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1119
|
-
"div",
|
|
1120
|
-
{
|
|
1121
|
-
"data-piece-square": algebraicOf3(index),
|
|
1122
|
-
"data-piece-cell": cell,
|
|
1123
|
-
style: {
|
|
1124
|
-
...SLOT_BASE_STYLE,
|
|
1125
|
-
gridColumnStart: col,
|
|
1126
|
-
gridRowStart: row,
|
|
1127
|
-
filter: `var(${cell <= 6 ? chunkD45G3J5E_cjs.CSS_VARS.PIECE_FILTER_WHITE : chunkD45G3J5E_cjs.CSS_VARS.PIECE_FILTER_BLACK}, none)`
|
|
1128
|
-
},
|
|
1129
|
-
children: pieces({ cell, square: index })
|
|
1130
|
-
}
|
|
1131
|
-
);
|
|
1132
|
-
}
|
|
1133
|
-
var PieceSlot = react.memo(PieceSlotImpl);
|
|
1134
|
-
PieceSlot.displayName = "PieceSlot";
|
|
1135
|
-
var CONTAINER_STYLE = Object.freeze({
|
|
1136
|
-
position: "absolute",
|
|
1137
|
-
inset: 0,
|
|
1138
|
-
display: "grid",
|
|
1139
|
-
gridTemplateColumns: "repeat(8, 1fr)",
|
|
1140
|
-
gridTemplateRows: "repeat(8, 1fr)",
|
|
1141
|
-
pointerEvents: "none"
|
|
1142
|
-
});
|
|
1143
|
-
var PieceLayer = react.memo(function PieceLayer2({
|
|
1144
|
-
model,
|
|
1145
|
-
orientation,
|
|
1146
|
-
pieces
|
|
1147
|
-
}) {
|
|
1148
|
-
const slots = [];
|
|
1149
|
-
for (let i = 0; i < 64; i++) {
|
|
1150
|
-
slots.push(
|
|
1151
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1152
|
-
PieceSlot,
|
|
1153
|
-
{
|
|
1154
|
-
index: i,
|
|
1155
|
-
model,
|
|
1156
|
-
orientation,
|
|
1157
|
-
pieces
|
|
1158
|
-
},
|
|
1159
|
-
i
|
|
1160
|
-
)
|
|
1161
|
-
);
|
|
1162
|
-
}
|
|
1163
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { "aria-hidden": "true", style: CONTAINER_STYLE, children: slots });
|
|
1164
|
-
});
|
|
1165
1822
|
function positionOf3(index, orientation) {
|
|
1166
1823
|
const file = index & 7;
|
|
1167
1824
|
const rank = index >> 3;
|
|
@@ -1211,7 +1868,7 @@ function PremoveLayerInner({ model, orientation, pieces, from, to }) {
|
|
|
1211
1868
|
top: `${origin.y}%`,
|
|
1212
1869
|
width: "12.5%",
|
|
1213
1870
|
height: "12.5%",
|
|
1214
|
-
background:
|
|
1871
|
+
background: chunkN4WTPXFC_cjs.DEFAULT_PREMOVE_TINT,
|
|
1215
1872
|
opacity: 0.5
|
|
1216
1873
|
}
|
|
1217
1874
|
}
|
|
@@ -1225,7 +1882,7 @@ function PremoveLayerInner({ model, orientation, pieces, from, to }) {
|
|
|
1225
1882
|
top: `${target.y}%`,
|
|
1226
1883
|
width: "12.5%",
|
|
1227
1884
|
height: "12.5%",
|
|
1228
|
-
background:
|
|
1885
|
+
background: chunkN4WTPXFC_cjs.DEFAULT_PREMOVE_TINT
|
|
1229
1886
|
}
|
|
1230
1887
|
}
|
|
1231
1888
|
),
|
|
@@ -1260,20 +1917,20 @@ function positionOf4(index, orientation) {
|
|
|
1260
1917
|
return { x: col * 12.5, y: row * 12.5 };
|
|
1261
1918
|
}
|
|
1262
1919
|
var CHOICE_ORDER = [
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1920
|
+
chunkFUP2LDMO_cjs.PieceType.Queen,
|
|
1921
|
+
chunkFUP2LDMO_cjs.PieceType.Knight,
|
|
1922
|
+
chunkFUP2LDMO_cjs.PieceType.Rook,
|
|
1923
|
+
chunkFUP2LDMO_cjs.PieceType.Bishop
|
|
1267
1924
|
];
|
|
1268
1925
|
var SHORTCUTS = {
|
|
1269
|
-
q:
|
|
1270
|
-
r:
|
|
1271
|
-
b:
|
|
1272
|
-
n:
|
|
1273
|
-
Q:
|
|
1274
|
-
R:
|
|
1275
|
-
B:
|
|
1276
|
-
N:
|
|
1926
|
+
q: chunkFUP2LDMO_cjs.PieceType.Queen,
|
|
1927
|
+
r: chunkFUP2LDMO_cjs.PieceType.Rook,
|
|
1928
|
+
b: chunkFUP2LDMO_cjs.PieceType.Bishop,
|
|
1929
|
+
n: chunkFUP2LDMO_cjs.PieceType.Knight,
|
|
1930
|
+
Q: chunkFUP2LDMO_cjs.PieceType.Queen,
|
|
1931
|
+
R: chunkFUP2LDMO_cjs.PieceType.Rook,
|
|
1932
|
+
B: chunkFUP2LDMO_cjs.PieceType.Bishop,
|
|
1933
|
+
N: chunkFUP2LDMO_cjs.PieceType.Knight
|
|
1277
1934
|
};
|
|
1278
1935
|
function PromotionOverlay({
|
|
1279
1936
|
from: _from,
|
|
@@ -1291,7 +1948,7 @@ function PromotionOverlay({
|
|
|
1291
1948
|
[getPromotionPieceAriaLabel, color]
|
|
1292
1949
|
);
|
|
1293
1950
|
const [activeAnnouncement, setActiveAnnouncement] = react.useState(
|
|
1294
|
-
() => getLabel(CHOICE_ORDER[0] ??
|
|
1951
|
+
() => getLabel(CHOICE_ORDER[0] ?? chunkFUP2LDMO_cjs.PieceType.Queen)
|
|
1295
1952
|
);
|
|
1296
1953
|
react.useEffect(() => {
|
|
1297
1954
|
buttonRefs.current[0]?.focus();
|
|
@@ -1373,7 +2030,7 @@ function PromotionOverlay({
|
|
|
1373
2030
|
{
|
|
1374
2031
|
role: "dialog",
|
|
1375
2032
|
"aria-modal": "true",
|
|
1376
|
-
"aria-label": `Choose promotion piece at ${
|
|
2033
|
+
"aria-label": `Choose promotion piece at ${algebraicOf5(to)}`,
|
|
1377
2034
|
onClick: (e) => e.stopPropagation(),
|
|
1378
2035
|
style: {
|
|
1379
2036
|
position: "absolute",
|
|
@@ -1389,7 +2046,7 @@ function PromotionOverlay({
|
|
|
1389
2046
|
overflow: "hidden"
|
|
1390
2047
|
},
|
|
1391
2048
|
children: CHOICE_ORDER.map((piece, index) => {
|
|
1392
|
-
const cell =
|
|
2049
|
+
const cell = chunkFUP2LDMO_cjs.encodeBoardCell(color, piece);
|
|
1393
2050
|
const label = getLabel(piece);
|
|
1394
2051
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1395
2052
|
"button",
|
|
@@ -1441,19 +2098,19 @@ var srOnlyStyle2 = {
|
|
|
1441
2098
|
};
|
|
1442
2099
|
function pieceName2(t) {
|
|
1443
2100
|
switch (t) {
|
|
1444
|
-
case
|
|
2101
|
+
case chunkFUP2LDMO_cjs.PieceType.Queen:
|
|
1445
2102
|
return "Queen";
|
|
1446
|
-
case
|
|
2103
|
+
case chunkFUP2LDMO_cjs.PieceType.Rook:
|
|
1447
2104
|
return "Rook";
|
|
1448
|
-
case
|
|
2105
|
+
case chunkFUP2LDMO_cjs.PieceType.Bishop:
|
|
1449
2106
|
return "Bishop";
|
|
1450
|
-
case
|
|
2107
|
+
case chunkFUP2LDMO_cjs.PieceType.Knight:
|
|
1451
2108
|
return "Knight";
|
|
1452
2109
|
default:
|
|
1453
2110
|
return "Piece";
|
|
1454
2111
|
}
|
|
1455
2112
|
}
|
|
1456
|
-
function
|
|
2113
|
+
function algebraicOf5(index) {
|
|
1457
2114
|
const file = index & 7;
|
|
1458
2115
|
const rank = index >> 3;
|
|
1459
2116
|
return `${String.fromCharCode(97 + file)}${rank + 1}`;
|
|
@@ -1469,13 +2126,13 @@ function StaticPieceLayer({ board, orientation, pieces }) {
|
|
|
1469
2126
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1470
2127
|
"div",
|
|
1471
2128
|
{
|
|
1472
|
-
"data-piece-square":
|
|
2129
|
+
"data-piece-square": algebraicOf(index),
|
|
1473
2130
|
"data-piece-cell": cell,
|
|
1474
2131
|
style: {
|
|
1475
2132
|
...SLOT_BASE_STYLE,
|
|
1476
2133
|
gridColumnStart: col,
|
|
1477
2134
|
gridRowStart: row,
|
|
1478
|
-
filter: `var(${cell <= 6 ?
|
|
2135
|
+
filter: `var(${cell <= 6 ? chunkN4WTPXFC_cjs.CSS_VARS.PIECE_FILTER_WHITE : chunkN4WTPXFC_cjs.CSS_VARS.PIECE_FILTER_BLACK}, none)`
|
|
1479
2136
|
},
|
|
1480
2137
|
children: pieces({ cell, square: index })
|
|
1481
2138
|
},
|
|
@@ -1487,7 +2144,7 @@ function StaticPieceLayer({ board, orientation, pieces }) {
|
|
|
1487
2144
|
}
|
|
1488
2145
|
var DEFAULT_DURATION_MS = 60;
|
|
1489
2146
|
var DEFAULT_EASING = "cubic-bezier(0.22, 0.61, 0.36, 1)";
|
|
1490
|
-
function
|
|
2147
|
+
function algebraicOf6(index) {
|
|
1491
2148
|
const file = index & 7;
|
|
1492
2149
|
const rank = index >> 3;
|
|
1493
2150
|
return `${String.fromCharCode(97 + file)}${rank + 1}`;
|
|
@@ -1535,7 +2192,7 @@ function runAnimations(descriptors, container, orientation, duration, easing) {
|
|
|
1535
2192
|
case "en-passant":
|
|
1536
2193
|
case "promotion": {
|
|
1537
2194
|
const toEl = container.querySelector(
|
|
1538
|
-
`[data-piece-square="${
|
|
2195
|
+
`[data-piece-square="${algebraicOf6(d.to)}"]`
|
|
1539
2196
|
);
|
|
1540
2197
|
if (toEl === null) break;
|
|
1541
2198
|
const { dx, dy } = deltaFromTo(d.from, d.to, sqSize, orientation);
|
|
@@ -1544,10 +2201,10 @@ function runAnimations(descriptors, container, orientation, duration, easing) {
|
|
|
1544
2201
|
}
|
|
1545
2202
|
case "castle": {
|
|
1546
2203
|
const kingEl = container.querySelector(
|
|
1547
|
-
`[data-piece-square="${
|
|
2204
|
+
`[data-piece-square="${algebraicOf6(d.kingTo)}"]`
|
|
1548
2205
|
);
|
|
1549
2206
|
const rookEl = container.querySelector(
|
|
1550
|
-
`[data-piece-square="${
|
|
2207
|
+
`[data-piece-square="${algebraicOf6(d.rookTo)}"]`
|
|
1551
2208
|
);
|
|
1552
2209
|
if (kingEl !== null) {
|
|
1553
2210
|
const { dx, dy } = deltaFromTo(d.kingFrom, d.kingTo, sqSize, orientation);
|
|
@@ -1591,39 +2248,6 @@ function AnimationRunner({
|
|
|
1591
2248
|
}, [historyPly, model, containerRef, orientation, duration, easing, skipNextRef]);
|
|
1592
2249
|
return null;
|
|
1593
2250
|
}
|
|
1594
|
-
|
|
1595
|
-
// src/lib/geometry.ts
|
|
1596
|
-
function getSquareAtPoint(container, clientX, clientY, orientation) {
|
|
1597
|
-
const rect = container.getBoundingClientRect();
|
|
1598
|
-
const relX = clientX - rect.left;
|
|
1599
|
-
const relY = clientY - rect.top;
|
|
1600
|
-
if (relX < 0 || relY < 0 || relX >= rect.width || relY >= rect.height) return null;
|
|
1601
|
-
const col = Math.floor(relX / rect.width * 8);
|
|
1602
|
-
const row = Math.floor(relY / rect.height * 8);
|
|
1603
|
-
const file = orientation === "white" ? col : 7 - col;
|
|
1604
|
-
const rank = orientation === "white" ? 7 - row : row;
|
|
1605
|
-
return rank * 8 + file;
|
|
1606
|
-
}
|
|
1607
|
-
function getPointAtSquareCentre(container, square, orientation) {
|
|
1608
|
-
const rect = container.getBoundingClientRect();
|
|
1609
|
-
const sqW = rect.width / 8;
|
|
1610
|
-
const sqH = rect.height / 8;
|
|
1611
|
-
const file = square & 7;
|
|
1612
|
-
const rank = square >> 3;
|
|
1613
|
-
const col = orientation === "white" ? file : 7 - file;
|
|
1614
|
-
const row = orientation === "white" ? 7 - rank : rank;
|
|
1615
|
-
return {
|
|
1616
|
-
x: rect.left + sqW * col + sqW / 2,
|
|
1617
|
-
y: rect.top + sqH * row + sqH / 2
|
|
1618
|
-
};
|
|
1619
|
-
}
|
|
1620
|
-
function algebraicOf6(square) {
|
|
1621
|
-
const file = square & 7;
|
|
1622
|
-
const rank = square >> 3;
|
|
1623
|
-
return `${String.fromCharCode(97 + file)}${rank + 1}`;
|
|
1624
|
-
}
|
|
1625
|
-
|
|
1626
|
-
// src/hooks/use-arrow-gesture.ts
|
|
1627
2251
|
function colorForModifiers(e, palette) {
|
|
1628
2252
|
if (e.shiftKey) return palette.shift;
|
|
1629
2253
|
if (e.altKey) return palette.alt;
|
|
@@ -1727,7 +2351,7 @@ function useArrowGesture(options) {
|
|
|
1727
2351
|
function wouldPromote(fromCell, toIndex) {
|
|
1728
2352
|
if (fromCell === 0) return false;
|
|
1729
2353
|
const pieceType = (fromCell - 1) % 6;
|
|
1730
|
-
if (pieceType !==
|
|
2354
|
+
if (pieceType !== chunkFUP2LDMO_cjs.PieceType.Pawn) return false;
|
|
1731
2355
|
const toRank = toIndex >> 3;
|
|
1732
2356
|
return toRank === 0 || toRank === 7;
|
|
1733
2357
|
}
|
|
@@ -1738,7 +2362,7 @@ function useClickToMove(model, onMove, onPromotionNeeded, enabled = true) {
|
|
|
1738
2362
|
if (model === null) return;
|
|
1739
2363
|
const snap = model.getSnapshot();
|
|
1740
2364
|
const cell = snap.board[index] ?? 0;
|
|
1741
|
-
const pieceColour = cell === 0 ? -1 : cell > 6 ?
|
|
2365
|
+
const pieceColour = cell === 0 ? -1 : cell > 6 ? chunkFUP2LDMO_cjs.Color.Black : chunkFUP2LDMO_cjs.Color.White;
|
|
1742
2366
|
if (snap.selected === null) {
|
|
1743
2367
|
if (pieceColour === snap.turn) model.selectSquare(index);
|
|
1744
2368
|
return;
|
|
@@ -1754,7 +2378,7 @@ function useClickToMove(model, onMove, onPromotionNeeded, enabled = true) {
|
|
|
1754
2378
|
onPromotionNeeded(snap.selected, index);
|
|
1755
2379
|
return;
|
|
1756
2380
|
}
|
|
1757
|
-
const played2 = model.tryMove(snap.selected, index,
|
|
2381
|
+
const played2 = model.tryMove(snap.selected, index, chunkFUP2LDMO_cjs.PieceType.Queen);
|
|
1758
2382
|
if (played2 !== null && onMove !== void 0) onMove(played2);
|
|
1759
2383
|
return;
|
|
1760
2384
|
}
|
|
@@ -1866,7 +2490,7 @@ function useCursorController(model, containerRef, allowDrag, allowPremove) {
|
|
|
1866
2490
|
};
|
|
1867
2491
|
}, [model, containerRef, allowDrag, allowPremove]);
|
|
1868
2492
|
}
|
|
1869
|
-
var GHOST_OPACITY_VAR =
|
|
2493
|
+
var GHOST_OPACITY_VAR = chunkN4WTPXFC_cjs.CSS_VARS.DRAG_GHOST_OPACITY;
|
|
1870
2494
|
function useDrag(options) {
|
|
1871
2495
|
const {
|
|
1872
2496
|
game,
|
|
@@ -1888,7 +2512,7 @@ function useDrag(options) {
|
|
|
1888
2512
|
if (!enabled) return;
|
|
1889
2513
|
const container = containerRef.current;
|
|
1890
2514
|
if (container === null || game === null) return;
|
|
1891
|
-
const controller =
|
|
2515
|
+
const controller = chunkFUP2LDMO_cjs.createDragController(
|
|
1892
2516
|
activationDistance === void 0 ? {} : { activationDistance }
|
|
1893
2517
|
);
|
|
1894
2518
|
let originEl = null;
|
|
@@ -1938,7 +2562,7 @@ function useDrag(options) {
|
|
|
1938
2562
|
controller.cancel();
|
|
1939
2563
|
return;
|
|
1940
2564
|
}
|
|
1941
|
-
const originLabel =
|
|
2565
|
+
const originLabel = algebraicOf2(evt.from);
|
|
1942
2566
|
originEl = container.querySelector(`[data-piece-square="${originLabel}"]`);
|
|
1943
2567
|
if (originEl !== null) {
|
|
1944
2568
|
originEl.style.opacity = `var(${GHOST_OPACITY_VAR}, 0.35)`;
|
|
@@ -2187,7 +2811,7 @@ function useLastMoveController(model, squareRefs, enabled) {
|
|
|
2187
2811
|
const lastMove = snap.lastMove;
|
|
2188
2812
|
let from = null;
|
|
2189
2813
|
let to = null;
|
|
2190
|
-
if (lastMove !== null) {
|
|
2814
|
+
if (lastMove !== null && !chunkFUP2LDMO_cjs.isNullMove(lastMove)) {
|
|
2191
2815
|
from = lastMove & 63;
|
|
2192
2816
|
to = lastMove >> 6 & 63;
|
|
2193
2817
|
}
|
|
@@ -2597,6 +3221,9 @@ var ILLEGAL_FLASH_HOLD_MS = 320;
|
|
|
2597
3221
|
var DEFAULT_POSITION_SYNC_DURATION_MS = 60;
|
|
2598
3222
|
var DEFAULT_POSITION_SYNC_EASING = "cubic-bezier(0.22, 0.61, 0.36, 1)";
|
|
2599
3223
|
var UCI_TRANSITION_RE = /^([a-h][1-8])([a-h][1-8])([nbrq])?$/i;
|
|
3224
|
+
function isNullTransition(transition) {
|
|
3225
|
+
return chunkFUP2LDMO_cjs.isNullMoveUci(transition.uci);
|
|
3226
|
+
}
|
|
2600
3227
|
function prefersReducedMotion3() {
|
|
2601
3228
|
if (typeof window === "undefined" || typeof window.matchMedia !== "function") {
|
|
2602
3229
|
return false;
|
|
@@ -2644,6 +3271,7 @@ function castleRookTransition(from, to) {
|
|
|
2644
3271
|
};
|
|
2645
3272
|
}
|
|
2646
3273
|
function transitionSquares(transition) {
|
|
3274
|
+
if (isNullTransition(transition)) return [];
|
|
2647
3275
|
const parsed = UCI_TRANSITION_RE.exec(transition.uci.trim().toLowerCase());
|
|
2648
3276
|
if (parsed === null) return [];
|
|
2649
3277
|
const moveFrom = parsed[1] ?? "";
|
|
@@ -2654,6 +3282,7 @@ function transitionSquares(transition) {
|
|
|
2654
3282
|
return transition.direction === "forward" ? forward : forward.map((item) => ({ from: item.to, to: item.from }));
|
|
2655
3283
|
}
|
|
2656
3284
|
function parseTransitionMove(transition) {
|
|
3285
|
+
if (isNullTransition(transition)) return null;
|
|
2657
3286
|
const parsed = UCI_TRANSITION_RE.exec(transition.uci.trim().toLowerCase());
|
|
2658
3287
|
if (parsed === null) return null;
|
|
2659
3288
|
const from = parsed[1];
|
|
@@ -2666,7 +3295,7 @@ function parseTransitionMove(transition) {
|
|
|
2666
3295
|
};
|
|
2667
3296
|
}
|
|
2668
3297
|
function isPawn(cell) {
|
|
2669
|
-
return !
|
|
3298
|
+
return !chunkFUP2LDMO_cjs.isEmptyCell(cell) && chunkFUP2LDMO_cjs.pieceTypeOf(cell) === 0;
|
|
2670
3299
|
}
|
|
2671
3300
|
function controlledFeedbackDescriptors(transition, previousBoard, nextBoard) {
|
|
2672
3301
|
if (transition === null || transition === void 0) return null;
|
|
@@ -2675,25 +3304,25 @@ function controlledFeedbackDescriptors(transition, previousBoard, nextBoard) {
|
|
|
2675
3304
|
const before = transition.direction === "forward" ? previousBoard : nextBoard;
|
|
2676
3305
|
const after = transition.direction === "forward" ? nextBoard : previousBoard;
|
|
2677
3306
|
const movingPiece = before[parsed.from] ?? 0;
|
|
2678
|
-
if (
|
|
3307
|
+
if (chunkFUP2LDMO_cjs.isEmptyCell(movingPiece)) return null;
|
|
2679
3308
|
const fromFile = parsed.from & 7;
|
|
2680
3309
|
const toFile = parsed.to & 7;
|
|
2681
3310
|
const targetBefore = before[parsed.to] ?? 0;
|
|
2682
3311
|
const targetAfter = after[parsed.to] ?? 0;
|
|
2683
|
-
if (
|
|
3312
|
+
if (chunkFUP2LDMO_cjs.pieceTypeOf(movingPiece) === 5 && Math.abs(toFile - fromFile) === 2) {
|
|
2684
3313
|
return [{ kind: "castle" }];
|
|
2685
3314
|
}
|
|
2686
|
-
if (parsed.promotion !== null || isPawn(movingPiece) && (parsed.to >> 3 === 0 || parsed.to >> 3 === 7) && !
|
|
3315
|
+
if (parsed.promotion !== null || isPawn(movingPiece) && (parsed.to >> 3 === 0 || parsed.to >> 3 === 7) && !chunkFUP2LDMO_cjs.isEmptyCell(targetAfter) && chunkFUP2LDMO_cjs.pieceTypeOf(targetAfter) !== 0) {
|
|
2687
3316
|
return [{ kind: "promotion" }];
|
|
2688
3317
|
}
|
|
2689
|
-
if (!
|
|
3318
|
+
if (!chunkFUP2LDMO_cjs.isEmptyCell(targetBefore) && chunkFUP2LDMO_cjs.colorOf(targetBefore) !== chunkFUP2LDMO_cjs.colorOf(movingPiece)) {
|
|
2690
3319
|
return [{ kind: "capture" }];
|
|
2691
3320
|
}
|
|
2692
|
-
if (isPawn(movingPiece) && fromFile !== toFile &&
|
|
3321
|
+
if (isPawn(movingPiece) && fromFile !== toFile && chunkFUP2LDMO_cjs.isEmptyCell(targetBefore)) {
|
|
2693
3322
|
const capturedSquare = parsed.from & -8 | toFile;
|
|
2694
3323
|
const capturedBefore = before[capturedSquare] ?? 0;
|
|
2695
3324
|
const capturedAfter = after[capturedSquare] ?? 0;
|
|
2696
|
-
if (!
|
|
3325
|
+
if (!chunkFUP2LDMO_cjs.isEmptyCell(capturedBefore) && chunkFUP2LDMO_cjs.colorOf(capturedBefore) !== chunkFUP2LDMO_cjs.colorOf(movingPiece) && chunkFUP2LDMO_cjs.isEmptyCell(capturedAfter)) {
|
|
2697
3326
|
return [{ kind: "en-passant" }];
|
|
2698
3327
|
}
|
|
2699
3328
|
}
|
|
@@ -2761,8 +3390,8 @@ function Chessboard(props) {
|
|
|
2761
3390
|
managedArrows,
|
|
2762
3391
|
preserveUserArrowsOnPositionSync,
|
|
2763
3392
|
orientation = "white",
|
|
2764
|
-
theme =
|
|
2765
|
-
pieces =
|
|
3393
|
+
theme = chunkN4WTPXFC_cjs.defaultTheme,
|
|
3394
|
+
pieces = chunkN4WTPXFC_cjs.defaultPieces,
|
|
2766
3395
|
showCoordinates = true,
|
|
2767
3396
|
ranksPosition = "left",
|
|
2768
3397
|
showLegalTargets = "rings",
|
|
@@ -2801,7 +3430,7 @@ function Chessboard(props) {
|
|
|
2801
3430
|
const fallbackBoard = react.useMemo(() => {
|
|
2802
3431
|
if (fallbackFen === void 0 || fallbackFen === "") return null;
|
|
2803
3432
|
try {
|
|
2804
|
-
return
|
|
3433
|
+
return chunkN4WTPXFC_cjs.parseFenPlacement(fallbackFen);
|
|
2805
3434
|
} catch {
|
|
2806
3435
|
return null;
|
|
2807
3436
|
}
|
|
@@ -2879,10 +3508,10 @@ function Chessboard(props) {
|
|
|
2879
3508
|
]);
|
|
2880
3509
|
const palette = react.useMemo(() => {
|
|
2881
3510
|
const merged = {
|
|
2882
|
-
default:
|
|
2883
|
-
shift:
|
|
2884
|
-
alt:
|
|
2885
|
-
ctrl:
|
|
3511
|
+
default: chunkN4WTPXFC_cjs.defaultArrowColors.default,
|
|
3512
|
+
shift: chunkN4WTPXFC_cjs.defaultArrowColors.shift,
|
|
3513
|
+
alt: chunkN4WTPXFC_cjs.defaultArrowColors.alt,
|
|
3514
|
+
ctrl: chunkN4WTPXFC_cjs.defaultArrowColors.ctrl
|
|
2886
3515
|
};
|
|
2887
3516
|
if (arrowColors !== void 0) {
|
|
2888
3517
|
for (const k in arrowColors) {
|
|
@@ -3200,15 +3829,15 @@ function useChessGame(options = {}) {
|
|
|
3200
3829
|
const { fen, ...modelOptions } = options;
|
|
3201
3830
|
const [initialModelOptions] = react.useState(() => modelOptions);
|
|
3202
3831
|
const [model, setModel] = react.useState(() => {
|
|
3203
|
-
const adapter =
|
|
3204
|
-
return
|
|
3832
|
+
const adapter = chunkFUP2LDMO_cjs.createGigachessAdapter(fen);
|
|
3833
|
+
return chunkFUP2LDMO_cjs.createBoardModel(adapter, modelOptions);
|
|
3205
3834
|
});
|
|
3206
3835
|
const prevFenRef = react.useRef(fen);
|
|
3207
3836
|
react.useEffect(() => {
|
|
3208
3837
|
if (prevFenRef.current !== fen) {
|
|
3209
3838
|
prevFenRef.current = fen;
|
|
3210
|
-
const adapter =
|
|
3211
|
-
const nextModel =
|
|
3839
|
+
const adapter = chunkFUP2LDMO_cjs.createGigachessAdapter(fen);
|
|
3840
|
+
const nextModel = chunkFUP2LDMO_cjs.createBoardModel(adapter, initialModelOptions);
|
|
3212
3841
|
setModel((prev) => {
|
|
3213
3842
|
prev.dispose();
|
|
3214
3843
|
return nextModel;
|
|
@@ -3224,68 +3853,100 @@ function useChessGame(options = {}) {
|
|
|
3224
3853
|
}
|
|
3225
3854
|
|
|
3226
3855
|
// src/index.ts
|
|
3227
|
-
var PACKAGE_VERSION = "1.
|
|
3856
|
+
var PACKAGE_VERSION = "1.5.0";
|
|
3228
3857
|
|
|
3229
3858
|
Object.defineProperty(exports, "Color", {
|
|
3230
3859
|
enumerable: true,
|
|
3231
|
-
get: function () { return
|
|
3860
|
+
get: function () { return chunkFUP2LDMO_cjs.Color; }
|
|
3861
|
+
});
|
|
3862
|
+
Object.defineProperty(exports, "NULL_MOVE_SAN", {
|
|
3863
|
+
enumerable: true,
|
|
3864
|
+
get: function () { return chunkFUP2LDMO_cjs.NULL_MOVE_SAN; }
|
|
3865
|
+
});
|
|
3866
|
+
Object.defineProperty(exports, "NULL_MOVE_SANS", {
|
|
3867
|
+
enumerable: true,
|
|
3868
|
+
get: function () { return chunkFUP2LDMO_cjs.NULL_MOVE_SANS; }
|
|
3869
|
+
});
|
|
3870
|
+
Object.defineProperty(exports, "NULL_MOVE_UCI", {
|
|
3871
|
+
enumerable: true,
|
|
3872
|
+
get: function () { return chunkFUP2LDMO_cjs.NULL_MOVE_UCI; }
|
|
3873
|
+
});
|
|
3874
|
+
Object.defineProperty(exports, "NULL_MOVE_WORD", {
|
|
3875
|
+
enumerable: true,
|
|
3876
|
+
get: function () { return chunkFUP2LDMO_cjs.NULL_MOVE_WORD; }
|
|
3232
3877
|
});
|
|
3233
3878
|
Object.defineProperty(exports, "PieceType", {
|
|
3234
3879
|
enumerable: true,
|
|
3235
|
-
get: function () { return
|
|
3880
|
+
get: function () { return chunkFUP2LDMO_cjs.PieceType; }
|
|
3236
3881
|
});
|
|
3237
3882
|
Object.defineProperty(exports, "createBoardModel", {
|
|
3238
3883
|
enumerable: true,
|
|
3239
|
-
get: function () { return
|
|
3884
|
+
get: function () { return chunkFUP2LDMO_cjs.createBoardModel; }
|
|
3240
3885
|
});
|
|
3241
3886
|
Object.defineProperty(exports, "createGigachessAdapter", {
|
|
3242
3887
|
enumerable: true,
|
|
3243
|
-
get: function () { return
|
|
3888
|
+
get: function () { return chunkFUP2LDMO_cjs.createGigachessAdapter; }
|
|
3889
|
+
});
|
|
3890
|
+
Object.defineProperty(exports, "isNullMove", {
|
|
3891
|
+
enumerable: true,
|
|
3892
|
+
get: function () { return chunkFUP2LDMO_cjs.isNullMove; }
|
|
3893
|
+
});
|
|
3894
|
+
Object.defineProperty(exports, "isNullMoveSan", {
|
|
3895
|
+
enumerable: true,
|
|
3896
|
+
get: function () { return chunkFUP2LDMO_cjs.isNullMoveSan; }
|
|
3897
|
+
});
|
|
3898
|
+
Object.defineProperty(exports, "isNullMoveUci", {
|
|
3899
|
+
enumerable: true,
|
|
3900
|
+
get: function () { return chunkFUP2LDMO_cjs.isNullMoveUci; }
|
|
3244
3901
|
});
|
|
3245
3902
|
Object.defineProperty(exports, "packMove", {
|
|
3246
3903
|
enumerable: true,
|
|
3247
|
-
get: function () { return
|
|
3904
|
+
get: function () { return chunkFUP2LDMO_cjs.packMove; }
|
|
3248
3905
|
});
|
|
3249
3906
|
Object.defineProperty(exports, "preloadGigachessAdapter", {
|
|
3250
3907
|
enumerable: true,
|
|
3251
|
-
get: function () { return
|
|
3908
|
+
get: function () { return chunkFUP2LDMO_cjs.preloadGigachessAdapter; }
|
|
3252
3909
|
});
|
|
3253
3910
|
Object.defineProperty(exports, "unpackMove", {
|
|
3254
3911
|
enumerable: true,
|
|
3255
|
-
get: function () { return
|
|
3912
|
+
get: function () { return chunkFUP2LDMO_cjs.unpackMove; }
|
|
3256
3913
|
});
|
|
3257
3914
|
Object.defineProperty(exports, "CSS_VARS", {
|
|
3258
3915
|
enumerable: true,
|
|
3259
|
-
get: function () { return
|
|
3916
|
+
get: function () { return chunkN4WTPXFC_cjs.CSS_VARS; }
|
|
3260
3917
|
});
|
|
3261
3918
|
Object.defineProperty(exports, "DEFAULT_ILLEGAL_FLASH_TINT", {
|
|
3262
3919
|
enumerable: true,
|
|
3263
|
-
get: function () { return
|
|
3920
|
+
get: function () { return chunkN4WTPXFC_cjs.DEFAULT_ILLEGAL_FLASH_TINT; }
|
|
3264
3921
|
});
|
|
3265
3922
|
Object.defineProperty(exports, "DEFAULT_PREMOVE_TINT", {
|
|
3266
3923
|
enumerable: true,
|
|
3267
|
-
get: function () { return
|
|
3924
|
+
get: function () { return chunkN4WTPXFC_cjs.DEFAULT_PREMOVE_TINT; }
|
|
3268
3925
|
});
|
|
3269
3926
|
Object.defineProperty(exports, "defaultArrowColors", {
|
|
3270
3927
|
enumerable: true,
|
|
3271
|
-
get: function () { return
|
|
3928
|
+
get: function () { return chunkN4WTPXFC_cjs.defaultArrowColors; }
|
|
3272
3929
|
});
|
|
3273
3930
|
Object.defineProperty(exports, "defaultPieces", {
|
|
3274
3931
|
enumerable: true,
|
|
3275
|
-
get: function () { return
|
|
3932
|
+
get: function () { return chunkN4WTPXFC_cjs.defaultPieces; }
|
|
3276
3933
|
});
|
|
3277
3934
|
Object.defineProperty(exports, "defaultTheme", {
|
|
3278
3935
|
enumerable: true,
|
|
3279
|
-
get: function () { return
|
|
3936
|
+
get: function () { return chunkN4WTPXFC_cjs.defaultTheme; }
|
|
3280
3937
|
});
|
|
3281
3938
|
exports.AnimationRunner = AnimationRunner;
|
|
3939
|
+
exports.BoardEditor = BoardEditor;
|
|
3282
3940
|
exports.Chessboard = Chessboard;
|
|
3283
3941
|
exports.DEFAULT_MOVE_HAPTIC_PATTERNS = DEFAULT_MOVE_HAPTIC_PATTERNS;
|
|
3284
3942
|
exports.DEFAULT_MOVE_SOUND_SOURCES = DEFAULT_MOVE_SOUND_SOURCES;
|
|
3285
3943
|
exports.PACKAGE_VERSION = PACKAGE_VERSION;
|
|
3944
|
+
exports.algebraicOf = algebraicOf2;
|
|
3286
3945
|
exports.classifyMoveFeedback = classifyMoveFeedback;
|
|
3946
|
+
exports.formatFenPlacement = formatFenPlacement;
|
|
3287
3947
|
exports.getPointAtSquareCentre = getPointAtSquareCentre;
|
|
3288
3948
|
exports.getSquareAtPoint = getSquareAtPoint;
|
|
3949
|
+
exports.squareOf = squareOf;
|
|
3289
3950
|
exports.triggerHaptic = triggerHaptic;
|
|
3290
3951
|
exports.triggerMoveHaptic = triggerMoveHaptic;
|
|
3291
3952
|
exports.useArrowGesture = useArrowGesture;
|