gigaboard 1.4.1 → 1.5.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/{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 +879 -259
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +55 -8
- package/dist/index.d.ts +55 -8
- package/dist/index.js +786 -198
- 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,695 @@ 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
|
+
onClear,
|
|
351
|
+
onSetStartingPosition,
|
|
352
|
+
onToggleSideToMove
|
|
353
|
+
}) {
|
|
354
|
+
const containerRef = react.useRef(null);
|
|
355
|
+
const liveRegionRef = react.useRef(null);
|
|
356
|
+
const liveCounter = react.useRef(0);
|
|
357
|
+
const [board, setBoard] = react.useState(() => {
|
|
358
|
+
try {
|
|
359
|
+
return chunkN4WTPXFC_cjs.parseFenPlacement(fen);
|
|
360
|
+
} catch {
|
|
361
|
+
return new Uint8Array(64);
|
|
362
|
+
}
|
|
363
|
+
});
|
|
364
|
+
const [internalFocusedSquare, setInternalFocusedSquare] = react.useState(
|
|
365
|
+
() => orientation === "white" ? 28 : 36
|
|
366
|
+
// e4 or e5
|
|
367
|
+
);
|
|
368
|
+
const focusedSquare = propFocusedSquare ?? internalFocusedSquare;
|
|
369
|
+
const setFocusedSquare = setInternalFocusedSquare;
|
|
370
|
+
const [hasKeyboardFocus, setHasKeyboardFocus] = react.useState(false);
|
|
371
|
+
const [dragging, setDragging] = react.useState(null);
|
|
372
|
+
react.useEffect(() => {
|
|
373
|
+
try {
|
|
374
|
+
const nextBoard = chunkN4WTPXFC_cjs.parseFenPlacement(fen);
|
|
375
|
+
setBoard(nextBoard);
|
|
376
|
+
} catch {
|
|
377
|
+
}
|
|
378
|
+
}, [fen]);
|
|
379
|
+
const announce = react.useCallback(
|
|
380
|
+
(message) => {
|
|
381
|
+
onAnnounce?.(message);
|
|
382
|
+
const region = liveRegionRef.current;
|
|
383
|
+
if (region) {
|
|
384
|
+
liveCounter.current++;
|
|
385
|
+
region.setAttribute("data-live-id", String(liveCounter.current));
|
|
386
|
+
region.textContent = "";
|
|
387
|
+
void region.offsetHeight;
|
|
388
|
+
region.textContent = message;
|
|
389
|
+
}
|
|
390
|
+
},
|
|
391
|
+
[onAnnounce]
|
|
392
|
+
);
|
|
393
|
+
const getSquareDescription = react.useCallback(
|
|
394
|
+
(square, cell) => {
|
|
395
|
+
const sq = algebraicOf2(square);
|
|
396
|
+
if (getSquareAriaLabel) {
|
|
397
|
+
return getSquareAriaLabel(square, cell, sq);
|
|
398
|
+
}
|
|
399
|
+
return defaultSquareLabel(square, cell);
|
|
400
|
+
},
|
|
401
|
+
[getSquareAriaLabel]
|
|
402
|
+
);
|
|
403
|
+
const announceSquare = react.useCallback(
|
|
404
|
+
(square) => {
|
|
405
|
+
const cell = board[square] ?? 0;
|
|
406
|
+
const desc = getSquareDescription(square, cell);
|
|
407
|
+
announce(desc);
|
|
408
|
+
onSquareFocus?.(square, cell, algebraicOf2(square));
|
|
409
|
+
},
|
|
410
|
+
[announce, board, getSquareDescription, onSquareFocus]
|
|
411
|
+
);
|
|
412
|
+
const commitBoard = react.useCallback(
|
|
413
|
+
(nextBoard) => {
|
|
414
|
+
setBoard(nextBoard);
|
|
415
|
+
const newPlacement = formatFenPlacement(nextBoard);
|
|
416
|
+
const updatedFen = updateFenPlacement(fen, newPlacement);
|
|
417
|
+
onChange?.(updatedFen);
|
|
418
|
+
},
|
|
419
|
+
[fen, onChange]
|
|
420
|
+
);
|
|
421
|
+
const placePieceAt = react.useCallback(
|
|
422
|
+
(square, cellOrCode) => {
|
|
423
|
+
const targetCell = typeof cellOrCode === "string" ? cellFromPieceString(cellOrCode) : cellOrCode;
|
|
424
|
+
const currentCell = board[square] ?? 0;
|
|
425
|
+
const nextBoard = new Uint8Array(board);
|
|
426
|
+
if (targetCell !== 0 && currentCell === targetCell) {
|
|
427
|
+
nextBoard[square] = 0;
|
|
428
|
+
commitBoard(nextBoard);
|
|
429
|
+
onPieceChange?.(square, 0, algebraicOf2(square));
|
|
430
|
+
announce(`Piece removed from ${algebraicOf2(square)}`);
|
|
431
|
+
} else if (targetCell !== 0) {
|
|
432
|
+
nextBoard[square] = targetCell;
|
|
433
|
+
commitBoard(nextBoard);
|
|
434
|
+
onPieceChange?.(square, targetCell, algebraicOf2(square));
|
|
435
|
+
const name = pieceNameFromCell(targetCell);
|
|
436
|
+
announce(`${name} placed on ${algebraicOf2(square)}`);
|
|
437
|
+
const char = PIECE_CHARS[targetCell] ?? "";
|
|
438
|
+
const code = targetCell <= 6 ? `w${char}` : `b${char.toUpperCase()}`;
|
|
439
|
+
onSelectPiece?.(code);
|
|
440
|
+
} else {
|
|
441
|
+
nextBoard[square] = 0;
|
|
442
|
+
commitBoard(nextBoard);
|
|
443
|
+
onPieceChange?.(square, 0, algebraicOf2(square));
|
|
444
|
+
announce(`Piece removed from ${algebraicOf2(square)}`);
|
|
445
|
+
}
|
|
446
|
+
},
|
|
447
|
+
[announce, board, commitBoard, onPieceChange, onSelectPiece]
|
|
448
|
+
);
|
|
449
|
+
const removePieceAt = react.useCallback(
|
|
450
|
+
(square) => {
|
|
451
|
+
const current = board[square] ?? 0;
|
|
452
|
+
if (current === 0) {
|
|
453
|
+
announce(`${algebraicOf2(square)} is empty`);
|
|
454
|
+
return;
|
|
455
|
+
}
|
|
456
|
+
const nextBoard = new Uint8Array(board);
|
|
457
|
+
nextBoard[square] = 0;
|
|
458
|
+
commitBoard(nextBoard);
|
|
459
|
+
onPieceChange?.(square, 0, algebraicOf2(square));
|
|
460
|
+
announce(`Piece removed from ${algebraicOf2(square)}`);
|
|
461
|
+
},
|
|
462
|
+
[announce, board, commitBoard, onPieceChange]
|
|
463
|
+
);
|
|
464
|
+
const handleKeyDown = react.useCallback(
|
|
465
|
+
(e) => {
|
|
466
|
+
if (e.altKey || e.ctrlKey || e.metaKey) return;
|
|
467
|
+
if (e.key.startsWith("Arrow")) {
|
|
468
|
+
if (e.shiftKey) return;
|
|
469
|
+
e.preventDefault();
|
|
470
|
+
const dir = e.key === "ArrowUp" ? "up" : e.key === "ArrowDown" ? "down" : e.key === "ArrowLeft" ? "left" : "right";
|
|
471
|
+
const next = moveSquare(focusedSquare, dir, orientation);
|
|
472
|
+
setFocusedSquare(next);
|
|
473
|
+
announceSquare(next);
|
|
474
|
+
return;
|
|
475
|
+
}
|
|
476
|
+
if (e.key === "Home" || e.key === "End") {
|
|
477
|
+
e.preventDefault();
|
|
478
|
+
const next = rankEndSquare(focusedSquare, e.key === "Home" ? "home" : "end", orientation);
|
|
479
|
+
setFocusedSquare(next);
|
|
480
|
+
announceSquare(next);
|
|
481
|
+
return;
|
|
482
|
+
}
|
|
483
|
+
if (e.key === "Backspace" || e.key === "Delete" || e.key === "x" || e.key === "X") {
|
|
484
|
+
e.preventDefault();
|
|
485
|
+
removePieceAt(focusedSquare);
|
|
486
|
+
return;
|
|
487
|
+
}
|
|
488
|
+
if (e.key === "c" || e.key === "C") {
|
|
489
|
+
e.preventDefault();
|
|
490
|
+
if (onClear) {
|
|
491
|
+
onClear();
|
|
492
|
+
} else {
|
|
493
|
+
commitBoard(new Uint8Array(64));
|
|
494
|
+
announce("Board cleared");
|
|
495
|
+
}
|
|
496
|
+
return;
|
|
497
|
+
}
|
|
498
|
+
if (e.key === "s" || e.key === "S") {
|
|
499
|
+
e.preventDefault();
|
|
500
|
+
if (onSetStartingPosition) {
|
|
501
|
+
onSetStartingPosition();
|
|
502
|
+
} else {
|
|
503
|
+
commitBoard(chunkN4WTPXFC_cjs.parseFenPlacement(chunkN4WTPXFC_cjs.STARTING_FEN));
|
|
504
|
+
announce("Starting position");
|
|
505
|
+
}
|
|
506
|
+
return;
|
|
507
|
+
}
|
|
508
|
+
if (e.key === "t" || e.key === "T") {
|
|
509
|
+
e.preventDefault();
|
|
510
|
+
onToggleSideToMove?.();
|
|
511
|
+
return;
|
|
512
|
+
}
|
|
513
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
514
|
+
e.preventDefault();
|
|
515
|
+
if (selectedPiece) {
|
|
516
|
+
const piece = e.shiftKey ? getOppositePieceString(selectedPiece) : selectedPiece;
|
|
517
|
+
if (piece) placePieceAt(focusedSquare, piece);
|
|
518
|
+
}
|
|
519
|
+
return;
|
|
520
|
+
}
|
|
521
|
+
const pieceCell = cellFromKey(e.key);
|
|
522
|
+
if (pieceCell !== 0) {
|
|
523
|
+
e.preventDefault();
|
|
524
|
+
placePieceAt(focusedSquare, pieceCell);
|
|
525
|
+
}
|
|
526
|
+
},
|
|
527
|
+
[
|
|
528
|
+
announce,
|
|
529
|
+
announceSquare,
|
|
530
|
+
commitBoard,
|
|
531
|
+
focusedSquare,
|
|
532
|
+
onClear,
|
|
533
|
+
onSetStartingPosition,
|
|
534
|
+
onToggleSideToMove,
|
|
535
|
+
orientation,
|
|
536
|
+
placePieceAt,
|
|
537
|
+
removePieceAt,
|
|
538
|
+
selectedPiece
|
|
539
|
+
]
|
|
540
|
+
);
|
|
541
|
+
const handlePointerDown = (e) => {
|
|
542
|
+
if (e.button !== 0) return;
|
|
543
|
+
const container = containerRef.current;
|
|
544
|
+
if (!container) return;
|
|
545
|
+
const sq = getSquareAtPoint(container, e.clientX, e.clientY, orientation);
|
|
546
|
+
if (sq === null) return;
|
|
547
|
+
container.focus();
|
|
548
|
+
setFocusedSquare(sq);
|
|
549
|
+
onSquareFocus?.(sq, board[sq] ?? 0, algebraicOf2(sq));
|
|
550
|
+
const cell = board[sq] ?? 0;
|
|
551
|
+
if (cell === 0) {
|
|
552
|
+
if (selectedPiece) {
|
|
553
|
+
placePieceAt(sq, selectedPiece);
|
|
554
|
+
}
|
|
555
|
+
return;
|
|
556
|
+
}
|
|
557
|
+
e.currentTarget.setPointerCapture(e.pointerId);
|
|
558
|
+
setDragging({
|
|
559
|
+
origin: sq,
|
|
560
|
+
cell,
|
|
561
|
+
x: e.clientX,
|
|
562
|
+
y: e.clientY
|
|
563
|
+
});
|
|
564
|
+
};
|
|
565
|
+
const handlePointerMove = (e) => {
|
|
566
|
+
if (!dragging) return;
|
|
567
|
+
setDragging((prev) => prev ? { ...prev, x: e.clientX, y: e.clientY } : null);
|
|
568
|
+
};
|
|
569
|
+
const handlePointerUp = (e) => {
|
|
570
|
+
if (!dragging) return;
|
|
571
|
+
const container = containerRef.current;
|
|
572
|
+
const originSq = dragging.origin;
|
|
573
|
+
const movedCell = dragging.cell;
|
|
574
|
+
setDragging(null);
|
|
575
|
+
if (!container) return;
|
|
576
|
+
const targetSq = getSquareAtPoint(container, e.clientX, e.clientY, orientation);
|
|
577
|
+
if (targetSq === null) {
|
|
578
|
+
removePieceAt(originSq);
|
|
579
|
+
return;
|
|
580
|
+
}
|
|
581
|
+
if (targetSq === originSq) {
|
|
582
|
+
if (selectedPiece) {
|
|
583
|
+
placePieceAt(originSq, selectedPiece);
|
|
584
|
+
}
|
|
585
|
+
return;
|
|
586
|
+
}
|
|
587
|
+
const nextBoard = new Uint8Array(board);
|
|
588
|
+
nextBoard[originSq] = 0;
|
|
589
|
+
nextBoard[targetSq] = movedCell;
|
|
590
|
+
commitBoard(nextBoard);
|
|
591
|
+
announce(`${pieceNameFromCell(movedCell)} moved to ${algebraicOf2(targetSq)}`);
|
|
592
|
+
setFocusedSquare(targetSq);
|
|
593
|
+
};
|
|
594
|
+
const handleContextMenu = (e) => {
|
|
595
|
+
e.preventDefault();
|
|
596
|
+
const container = containerRef.current;
|
|
597
|
+
if (!container) return;
|
|
598
|
+
const sq = getSquareAtPoint(container, e.clientX, e.clientY, orientation);
|
|
599
|
+
if (sq === null) return;
|
|
600
|
+
setFocusedSquare(sq);
|
|
601
|
+
if (selectedPiece) {
|
|
602
|
+
const opp = getOppositePieceString(selectedPiece);
|
|
603
|
+
if (opp) placePieceAt(sq, opp);
|
|
604
|
+
}
|
|
605
|
+
};
|
|
606
|
+
const squareOrder = react.useMemo(() => {
|
|
607
|
+
const squares = [];
|
|
608
|
+
if (orientation === "white") {
|
|
609
|
+
for (let rank = 7; rank >= 0; rank--) {
|
|
610
|
+
for (let file = 0; file < 8; file++) {
|
|
611
|
+
squares.push(rank * 8 + file);
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
} else {
|
|
615
|
+
for (let rank = 0; rank < 8; rank++) {
|
|
616
|
+
for (let file = 7; file >= 0; file--) {
|
|
617
|
+
squares.push(rank * 8 + file);
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
return squares;
|
|
622
|
+
}, [orientation]);
|
|
623
|
+
const containerStyle = {
|
|
624
|
+
position: "relative",
|
|
625
|
+
aspectRatio: "1 / 1",
|
|
626
|
+
width: "100%",
|
|
627
|
+
touchAction: "none",
|
|
628
|
+
outline: hasKeyboardFocus ? "3px solid var(--gb-editor-focus, #d97706)" : "none",
|
|
629
|
+
outlineOffset: "2px",
|
|
630
|
+
borderRadius: "8px",
|
|
631
|
+
...theme,
|
|
632
|
+
...style
|
|
633
|
+
};
|
|
634
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
635
|
+
"div",
|
|
636
|
+
{
|
|
637
|
+
ref: containerRef,
|
|
638
|
+
role: "application",
|
|
639
|
+
tabIndex: 0,
|
|
640
|
+
"aria-label": ariaLabel,
|
|
641
|
+
"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",
|
|
642
|
+
onKeyDown: handleKeyDown,
|
|
643
|
+
onFocus: (e) => {
|
|
644
|
+
if (e.target === e.currentTarget) {
|
|
645
|
+
setHasKeyboardFocus(true);
|
|
646
|
+
announceSquare(focusedSquare);
|
|
647
|
+
}
|
|
648
|
+
},
|
|
649
|
+
onBlur: () => setHasKeyboardFocus(false),
|
|
650
|
+
onPointerDown: handlePointerDown,
|
|
651
|
+
onPointerMove: handlePointerMove,
|
|
652
|
+
onPointerUp: handlePointerUp,
|
|
653
|
+
onPointerCancel: () => setDragging(null),
|
|
654
|
+
onContextMenu: handleContextMenu,
|
|
655
|
+
className,
|
|
656
|
+
style: containerStyle,
|
|
657
|
+
"data-gb-editor": "true",
|
|
658
|
+
"data-gb-orientation": orientation,
|
|
659
|
+
children: [
|
|
660
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
661
|
+
"div",
|
|
662
|
+
{
|
|
663
|
+
"aria-hidden": "true",
|
|
664
|
+
style: {
|
|
665
|
+
position: "absolute",
|
|
666
|
+
inset: 0,
|
|
667
|
+
display: "grid",
|
|
668
|
+
gridTemplateColumns: "repeat(8, 1fr)",
|
|
669
|
+
gridTemplateRows: "repeat(8, 1fr)",
|
|
670
|
+
pointerEvents: "none"
|
|
671
|
+
},
|
|
672
|
+
children: squareOrder.map((sq) => {
|
|
673
|
+
const file = sq & 7;
|
|
674
|
+
const rank = sq >> 3;
|
|
675
|
+
const isLight = (file + rank & 1) !== 0;
|
|
676
|
+
const isFocused = hasKeyboardFocus && focusedSquare === sq;
|
|
677
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
678
|
+
"div",
|
|
679
|
+
{
|
|
680
|
+
"data-square": algebraicOf2(sq),
|
|
681
|
+
style: {
|
|
682
|
+
position: "relative",
|
|
683
|
+
backgroundColor: `var(${isLight ? chunkN4WTPXFC_cjs.CSS_VARS.SQ_LIGHT : chunkN4WTPXFC_cjs.CSS_VARS.SQ_DARK})`,
|
|
684
|
+
backgroundImage: `var(${isLight ? chunkN4WTPXFC_cjs.CSS_VARS.SQ_LIGHT_IMAGE : chunkN4WTPXFC_cjs.CSS_VARS.SQ_DARK_IMAGE},none)`,
|
|
685
|
+
backgroundSize: `var(${chunkN4WTPXFC_cjs.CSS_VARS.SQ_IMAGE_SIZE},cover)`,
|
|
686
|
+
boxShadow: isFocused ? "inset 0 0 0 3px rgba(255, 206, 76, 0.95)" : void 0,
|
|
687
|
+
userSelect: "none"
|
|
688
|
+
}
|
|
689
|
+
},
|
|
690
|
+
sq
|
|
691
|
+
);
|
|
692
|
+
})
|
|
693
|
+
}
|
|
694
|
+
),
|
|
695
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
696
|
+
"div",
|
|
697
|
+
{
|
|
698
|
+
"aria-hidden": "true",
|
|
699
|
+
style: {
|
|
700
|
+
position: "absolute",
|
|
701
|
+
inset: 0,
|
|
702
|
+
display: "grid",
|
|
703
|
+
gridTemplateColumns: "repeat(8, 1fr)",
|
|
704
|
+
gridTemplateRows: "repeat(8, 1fr)",
|
|
705
|
+
pointerEvents: "none"
|
|
706
|
+
},
|
|
707
|
+
children: squareOrder.map((sq) => {
|
|
708
|
+
const cell = board[sq] ?? 0;
|
|
709
|
+
if (cell === 0) return null;
|
|
710
|
+
const isOrigin = dragging?.origin === sq;
|
|
711
|
+
const { col, row } = gridCoord(sq, orientation);
|
|
712
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
713
|
+
"div",
|
|
714
|
+
{
|
|
715
|
+
"data-piece-square": algebraicOf2(sq),
|
|
716
|
+
style: {
|
|
717
|
+
...SLOT_BASE_STYLE,
|
|
718
|
+
gridColumnStart: col,
|
|
719
|
+
gridRowStart: row,
|
|
720
|
+
opacity: isOrigin ? 0.25 : 1,
|
|
721
|
+
filter: `var(${cell <= 6 ? chunkN4WTPXFC_cjs.CSS_VARS.PIECE_FILTER_WHITE : chunkN4WTPXFC_cjs.CSS_VARS.PIECE_FILTER_BLACK}, none)`,
|
|
722
|
+
pointerEvents: "none"
|
|
723
|
+
},
|
|
724
|
+
children: pieces({ cell, square: sq })
|
|
725
|
+
},
|
|
726
|
+
sq
|
|
727
|
+
);
|
|
728
|
+
})
|
|
729
|
+
}
|
|
730
|
+
),
|
|
731
|
+
dragging && containerRef.current ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
732
|
+
"div",
|
|
733
|
+
{
|
|
734
|
+
"aria-hidden": "true",
|
|
735
|
+
style: {
|
|
736
|
+
position: "fixed",
|
|
737
|
+
left: dragging.x - 30,
|
|
738
|
+
top: dragging.y - 30,
|
|
739
|
+
width: 60,
|
|
740
|
+
height: 60,
|
|
741
|
+
pointerEvents: "none",
|
|
742
|
+
zIndex: 100,
|
|
743
|
+
filter: `var(${dragging.cell <= 6 ? chunkN4WTPXFC_cjs.CSS_VARS.PIECE_FILTER_WHITE : chunkN4WTPXFC_cjs.CSS_VARS.PIECE_FILTER_BLACK}, none)`
|
|
744
|
+
},
|
|
745
|
+
children: pieces({ cell: dragging.cell, square: dragging.origin })
|
|
746
|
+
}
|
|
747
|
+
) : null,
|
|
748
|
+
showCoordinates ? /* @__PURE__ */ jsxRuntime.jsx(Coordinates, { orientation }) : null,
|
|
749
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
750
|
+
"div",
|
|
751
|
+
{
|
|
752
|
+
ref: liveRegionRef,
|
|
753
|
+
role: "status",
|
|
754
|
+
"aria-live": "assertive",
|
|
755
|
+
"aria-atomic": "true",
|
|
756
|
+
style: {
|
|
757
|
+
position: "absolute",
|
|
758
|
+
width: 1,
|
|
759
|
+
height: 1,
|
|
760
|
+
padding: 0,
|
|
761
|
+
margin: -1,
|
|
762
|
+
overflow: "hidden",
|
|
763
|
+
clip: "rect(0, 0, 0, 0)",
|
|
764
|
+
whiteSpace: "nowrap",
|
|
765
|
+
border: 0
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
)
|
|
769
|
+
]
|
|
770
|
+
}
|
|
771
|
+
);
|
|
31
772
|
}
|
|
32
773
|
function squareCentrePct(index, orientation) {
|
|
33
774
|
const file = index & 7;
|
|
@@ -161,11 +902,12 @@ function computeDynamicAeroGeometry(text, style, fontSize, isTerminal = true) {
|
|
|
161
902
|
const resolvedStyle = style ?? "aero_chisel";
|
|
162
903
|
const hasText = Boolean(text && text.trim().length > 0);
|
|
163
904
|
if (!hasText) {
|
|
164
|
-
const
|
|
165
|
-
const
|
|
166
|
-
const
|
|
167
|
-
const
|
|
168
|
-
const
|
|
905
|
+
const scale2 = Math.max(1, fontSize / 2.45);
|
|
906
|
+
const tipX = 2.8 * scale2;
|
|
907
|
+
const shoulderX = 0.2 * scale2;
|
|
908
|
+
const rearX = -1.2 * scale2;
|
|
909
|
+
const dockX2 = -1.8 * scale2;
|
|
910
|
+
const halfH2 = 2.2 * scale2;
|
|
169
911
|
const path2 = `M ${rearX},${-halfH2} L ${shoulderX},${-halfH2} L ${tipX},0 L ${shoulderX},${halfH2} L ${rearX},${halfH2} C ${dockX2},${halfH2} ${dockX2},${-halfH2} ${rearX},${-halfH2} Z`;
|
|
170
912
|
return {
|
|
171
913
|
path: path2,
|
|
@@ -178,16 +920,17 @@ function computeDynamicAeroGeometry(text, style, fontSize, isTerminal = true) {
|
|
|
178
920
|
const charWidth = fontSize * 0.6;
|
|
179
921
|
const textWidth = text.length * charWidth;
|
|
180
922
|
const halfTextW = textWidth / 2;
|
|
181
|
-
const
|
|
182
|
-
const
|
|
923
|
+
const scale = Math.max(1, fontSize / 2.45);
|
|
924
|
+
const padX = 0.75 * scale;
|
|
925
|
+
const cabinW = Math.max(3.2 * scale, halfTextW + padX);
|
|
183
926
|
const halfH = Math.max(2.3, fontSize * 0.9);
|
|
184
|
-
const rearInset = 0.65;
|
|
927
|
+
const rearInset = 0.65 * scale;
|
|
185
928
|
const dockX = -cabinW - rearInset;
|
|
186
929
|
let frontLen = 0;
|
|
187
930
|
let path = "";
|
|
188
931
|
if (resolvedStyle === "aero_chisel") {
|
|
189
932
|
if (isTerminal) {
|
|
190
|
-
const noseLead = 1.25;
|
|
933
|
+
const noseLead = 1.25 * scale;
|
|
191
934
|
const tipX = cabinW + noseLead;
|
|
192
935
|
frontLen = tipX;
|
|
193
936
|
path = `M ${-cabinW},${-halfH} L ${cabinW},${-halfH} L ${tipX},0 L ${cabinW},${halfH} L ${-cabinW},${halfH} C ${dockX},${halfH} ${dockX},${-halfH} ${-cabinW},${-halfH} Z`;
|
|
@@ -606,7 +1349,7 @@ function injectFocusRingStyles() {
|
|
|
606
1349
|
`;
|
|
607
1350
|
document.head.appendChild(style);
|
|
608
1351
|
}
|
|
609
|
-
function
|
|
1352
|
+
function algebraicOf3(index) {
|
|
610
1353
|
const file = index & 7;
|
|
611
1354
|
const rank = index >> 3;
|
|
612
1355
|
return `${String.fromCharCode(97 + file)}${rank + 1}`;
|
|
@@ -625,7 +1368,7 @@ function SquareImpl({
|
|
|
625
1368
|
const rank = index >> 3;
|
|
626
1369
|
const isLight = (file + rank) % 2 === 1;
|
|
627
1370
|
const cell = useSquareCell(model, index);
|
|
628
|
-
const label = getSquareAriaLabel ? getSquareAriaLabel(index, cell) :
|
|
1371
|
+
const label = getSquareAriaLabel ? getSquareAriaLabel(index, cell) : algebraicOf3(index);
|
|
629
1372
|
const internalRef = react.useRef(null);
|
|
630
1373
|
const lastReportedFocusRef = react.useRef(false);
|
|
631
1374
|
const setRef = react.useCallback(
|
|
@@ -668,7 +1411,7 @@ function SquareImpl({
|
|
|
668
1411
|
"aria-rowindex": rank + 1,
|
|
669
1412
|
"aria-colindex": file + 1,
|
|
670
1413
|
tabIndex: isFocused ? 0 : -1,
|
|
671
|
-
"data-square":
|
|
1414
|
+
"data-square": algebraicOf3(index),
|
|
672
1415
|
"data-gb-square": "",
|
|
673
1416
|
"data-light": isLight ? "true" : "false",
|
|
674
1417
|
onClick: handleClick,
|
|
@@ -678,10 +1421,10 @@ function SquareImpl({
|
|
|
678
1421
|
// `backgroundColor` (not the `background` shorthand) so the
|
|
679
1422
|
// CSS `background-image` set by `useSelectionController` (or pseudo-elements)
|
|
680
1423
|
// can layer on top without clobbering this base colour.
|
|
681
|
-
backgroundColor: `var(${isLight ?
|
|
682
|
-
backgroundImage: `var(${isLight ?
|
|
683
|
-
backgroundSize: `var(${
|
|
684
|
-
backgroundBlendMode: `var(${
|
|
1424
|
+
backgroundColor: `var(${isLight ? chunkN4WTPXFC_cjs.CSS_VARS.SQ_LIGHT : chunkN4WTPXFC_cjs.CSS_VARS.SQ_DARK})`,
|
|
1425
|
+
backgroundImage: `var(${isLight ? chunkN4WTPXFC_cjs.CSS_VARS.SQ_LIGHT_IMAGE : chunkN4WTPXFC_cjs.CSS_VARS.SQ_DARK_IMAGE},none)`,
|
|
1426
|
+
backgroundSize: `var(${chunkN4WTPXFC_cjs.CSS_VARS.SQ_IMAGE_SIZE},cover)`,
|
|
1427
|
+
backgroundBlendMode: `var(${chunkN4WTPXFC_cjs.CSS_VARS.SQ_BLEND_MODE},normal)`,
|
|
685
1428
|
// Cursor is managed by `useCursorController` via injected CSS so
|
|
686
1429
|
// it can flip between `pointer` / `grab` / `grabbing` without a
|
|
687
1430
|
// React re-render per hover.
|
|
@@ -799,71 +1542,13 @@ function CheckLayerInner({ model, orientation }) {
|
|
|
799
1542
|
top: `${y}%`,
|
|
800
1543
|
width: "12.5%",
|
|
801
1544
|
height: "12.5%",
|
|
802
|
-
background: `var(${
|
|
1545
|
+
background: `var(${chunkN4WTPXFC_cjs.CSS_VARS.CHECK})`,
|
|
803
1546
|
pointerEvents: "none",
|
|
804
1547
|
zIndex: 2
|
|
805
1548
|
}
|
|
806
1549
|
}
|
|
807
1550
|
);
|
|
808
1551
|
}
|
|
809
|
-
var FILE_LETTERS = ["a", "b", "c", "d", "e", "f", "g", "h"];
|
|
810
|
-
function Coordinates({ orientation, ranksPosition = "left" }) {
|
|
811
|
-
const ranksOnRight = ranksPosition === "right";
|
|
812
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
813
|
-
"div",
|
|
814
|
-
{
|
|
815
|
-
"aria-hidden": "true",
|
|
816
|
-
style: {
|
|
817
|
-
position: "absolute",
|
|
818
|
-
inset: 0,
|
|
819
|
-
pointerEvents: "none",
|
|
820
|
-
fontSize: "min(1.6vmin, 11px)",
|
|
821
|
-
fontWeight: 600,
|
|
822
|
-
fontFamily: "system-ui, -apple-system, sans-serif"
|
|
823
|
-
},
|
|
824
|
-
children: [
|
|
825
|
-
FILE_LETTERS.map((letter, idx) => {
|
|
826
|
-
const col = orientation === "white" ? idx : 7 - idx;
|
|
827
|
-
const bottomRank = orientation === "white" ? 0 : 7;
|
|
828
|
-
const isLightSquare = (col + bottomRank) % 2 === 1;
|
|
829
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
830
|
-
"span",
|
|
831
|
-
{
|
|
832
|
-
style: {
|
|
833
|
-
position: "absolute",
|
|
834
|
-
left: `${col * 12.5 + 10}%`,
|
|
835
|
-
bottom: "1%",
|
|
836
|
-
color: `var(${isLightSquare ? chunkD45G3J5E_cjs.CSS_VARS.COORDINATE_LIGHT : chunkD45G3J5E_cjs.CSS_VARS.COORDINATE_DARK})`
|
|
837
|
-
},
|
|
838
|
-
children: letter
|
|
839
|
-
},
|
|
840
|
-
`file-${letter}`
|
|
841
|
-
);
|
|
842
|
-
}),
|
|
843
|
-
FILE_LETTERS.map((_, idx) => {
|
|
844
|
-
const rank = idx;
|
|
845
|
-
const row = orientation === "white" ? 7 - rank : rank;
|
|
846
|
-
const edgeFile = ranksOnRight ? orientation === "white" ? 7 : 0 : orientation === "white" ? 0 : 7;
|
|
847
|
-
const isLightSquare = (edgeFile + rank) % 2 === 1;
|
|
848
|
-
const sideStyle = ranksOnRight ? { right: "1%" } : { left: "1%" };
|
|
849
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
850
|
-
"span",
|
|
851
|
-
{
|
|
852
|
-
style: {
|
|
853
|
-
position: "absolute",
|
|
854
|
-
top: `${row * 12.5 + 1}%`,
|
|
855
|
-
...sideStyle,
|
|
856
|
-
color: `var(${isLightSquare ? chunkD45G3J5E_cjs.CSS_VARS.COORDINATE_LIGHT : chunkD45G3J5E_cjs.CSS_VARS.COORDINATE_DARK})`
|
|
857
|
-
},
|
|
858
|
-
children: rank + 1
|
|
859
|
-
},
|
|
860
|
-
`rank-${rank}`
|
|
861
|
-
);
|
|
862
|
-
})
|
|
863
|
-
]
|
|
864
|
-
}
|
|
865
|
-
);
|
|
866
|
-
}
|
|
867
1552
|
var WRAPPER_STYLE = Object.freeze({
|
|
868
1553
|
position: "absolute",
|
|
869
1554
|
top: 0,
|
|
@@ -900,7 +1585,7 @@ var DragLayer = react.forwardRef(function DragLayer2({ pieces }, ref) {
|
|
|
900
1585
|
"data-drag-cell": cell,
|
|
901
1586
|
style: {
|
|
902
1587
|
...SLOT_STYLE,
|
|
903
|
-
filter: `var(${cell <= 6 ?
|
|
1588
|
+
filter: `var(${cell <= 6 ? chunkN4WTPXFC_cjs.CSS_VARS.PIECE_FILTER_WHITE : chunkN4WTPXFC_cjs.CSS_VARS.PIECE_FILTER_BLACK}, none)`
|
|
904
1589
|
},
|
|
905
1590
|
children: child
|
|
906
1591
|
},
|
|
@@ -998,7 +1683,7 @@ function IllegalFlashLayer({ at, orientation }) {
|
|
|
998
1683
|
top: `${y}%`,
|
|
999
1684
|
width: "12.5%",
|
|
1000
1685
|
height: "12.5%",
|
|
1001
|
-
background:
|
|
1686
|
+
background: chunkN4WTPXFC_cjs.DEFAULT_ILLEGAL_FLASH_TINT,
|
|
1002
1687
|
opacity: 0,
|
|
1003
1688
|
pointerEvents: "none",
|
|
1004
1689
|
zIndex: 5
|
|
@@ -1006,7 +1691,7 @@ function IllegalFlashLayer({ at, orientation }) {
|
|
|
1006
1691
|
}
|
|
1007
1692
|
);
|
|
1008
1693
|
}
|
|
1009
|
-
function
|
|
1694
|
+
function algebraicOf4(index) {
|
|
1010
1695
|
const file = index & 7;
|
|
1011
1696
|
const rank = index >> 3;
|
|
1012
1697
|
return `${String.fromCharCode(97 + file)}${rank + 1}`;
|
|
@@ -1033,15 +1718,16 @@ function pieceName(cell) {
|
|
|
1033
1718
|
}
|
|
1034
1719
|
}
|
|
1035
1720
|
function announcementFor(lastMove, board, wasCapture) {
|
|
1036
|
-
const { from, to, kind, promotion } =
|
|
1721
|
+
const { from, to, kind, promotion } = chunkFUP2LDMO_cjs.decodePackedMove(lastMove);
|
|
1722
|
+
if (kind === "pass") return "Passes.";
|
|
1037
1723
|
if (kind === "castle") {
|
|
1038
1724
|
const isKingside = (to & 7) > (from & 7);
|
|
1039
1725
|
return isKingside ? "Castles kingside." : "Castles queenside.";
|
|
1040
1726
|
}
|
|
1041
1727
|
const landed = board[to] ?? 0;
|
|
1042
1728
|
const name = pieceName(landed);
|
|
1043
|
-
const fromSq =
|
|
1044
|
-
const toSq =
|
|
1729
|
+
const fromSq = algebraicOf4(from);
|
|
1730
|
+
const toSq = algebraicOf4(to);
|
|
1045
1731
|
if (kind === "promotion" && promotion !== null) {
|
|
1046
1732
|
const promoted = promotion === 1 ? "knight" : promotion === 2 ? "bishop" : promotion === 3 ? "rook" : "queen";
|
|
1047
1733
|
const action = wasCapture ? "captures and promotes" : "promotes";
|
|
@@ -1090,76 +1776,6 @@ function LiveRegion({ model }) {
|
|
|
1090
1776
|
}
|
|
1091
1777
|
);
|
|
1092
1778
|
}
|
|
1093
|
-
function gridCoord(index, orientation) {
|
|
1094
|
-
const file = index & 7;
|
|
1095
|
-
const rank = index >> 3;
|
|
1096
|
-
const col = orientation === "white" ? file + 1 : 8 - file;
|
|
1097
|
-
const row = orientation === "white" ? 8 - rank : rank + 1;
|
|
1098
|
-
return { col, row };
|
|
1099
|
-
}
|
|
1100
|
-
function algebraicOf3(index) {
|
|
1101
|
-
const file = index & 7;
|
|
1102
|
-
const rank = index >> 3;
|
|
1103
|
-
return `${String.fromCharCode(97 + file)}${rank + 1}`;
|
|
1104
|
-
}
|
|
1105
|
-
var SLOT_BASE_STYLE = Object.freeze({
|
|
1106
|
-
display: "flex",
|
|
1107
|
-
alignItems: "center",
|
|
1108
|
-
justifyContent: "center",
|
|
1109
|
-
pointerEvents: "none",
|
|
1110
|
-
containerType: "size"
|
|
1111
|
-
});
|
|
1112
|
-
function PieceSlotImpl({ index, model, orientation, pieces }) {
|
|
1113
|
-
const cell = useSquareCell(model, index);
|
|
1114
|
-
if (cell === 0) return null;
|
|
1115
|
-
const { col, row } = gridCoord(index, orientation);
|
|
1116
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1117
|
-
"div",
|
|
1118
|
-
{
|
|
1119
|
-
"data-piece-square": algebraicOf3(index),
|
|
1120
|
-
"data-piece-cell": cell,
|
|
1121
|
-
style: {
|
|
1122
|
-
...SLOT_BASE_STYLE,
|
|
1123
|
-
gridColumnStart: col,
|
|
1124
|
-
gridRowStart: row,
|
|
1125
|
-
filter: `var(${cell <= 6 ? chunkD45G3J5E_cjs.CSS_VARS.PIECE_FILTER_WHITE : chunkD45G3J5E_cjs.CSS_VARS.PIECE_FILTER_BLACK}, none)`
|
|
1126
|
-
},
|
|
1127
|
-
children: pieces({ cell, square: index })
|
|
1128
|
-
}
|
|
1129
|
-
);
|
|
1130
|
-
}
|
|
1131
|
-
var PieceSlot = react.memo(PieceSlotImpl);
|
|
1132
|
-
PieceSlot.displayName = "PieceSlot";
|
|
1133
|
-
var CONTAINER_STYLE = Object.freeze({
|
|
1134
|
-
position: "absolute",
|
|
1135
|
-
inset: 0,
|
|
1136
|
-
display: "grid",
|
|
1137
|
-
gridTemplateColumns: "repeat(8, 1fr)",
|
|
1138
|
-
gridTemplateRows: "repeat(8, 1fr)",
|
|
1139
|
-
pointerEvents: "none"
|
|
1140
|
-
});
|
|
1141
|
-
var PieceLayer = react.memo(function PieceLayer2({
|
|
1142
|
-
model,
|
|
1143
|
-
orientation,
|
|
1144
|
-
pieces
|
|
1145
|
-
}) {
|
|
1146
|
-
const slots = [];
|
|
1147
|
-
for (let i = 0; i < 64; i++) {
|
|
1148
|
-
slots.push(
|
|
1149
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1150
|
-
PieceSlot,
|
|
1151
|
-
{
|
|
1152
|
-
index: i,
|
|
1153
|
-
model,
|
|
1154
|
-
orientation,
|
|
1155
|
-
pieces
|
|
1156
|
-
},
|
|
1157
|
-
i
|
|
1158
|
-
)
|
|
1159
|
-
);
|
|
1160
|
-
}
|
|
1161
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { "aria-hidden": "true", style: CONTAINER_STYLE, children: slots });
|
|
1162
|
-
});
|
|
1163
1779
|
function positionOf3(index, orientation) {
|
|
1164
1780
|
const file = index & 7;
|
|
1165
1781
|
const rank = index >> 3;
|
|
@@ -1209,7 +1825,7 @@ function PremoveLayerInner({ model, orientation, pieces, from, to }) {
|
|
|
1209
1825
|
top: `${origin.y}%`,
|
|
1210
1826
|
width: "12.5%",
|
|
1211
1827
|
height: "12.5%",
|
|
1212
|
-
background:
|
|
1828
|
+
background: chunkN4WTPXFC_cjs.DEFAULT_PREMOVE_TINT,
|
|
1213
1829
|
opacity: 0.5
|
|
1214
1830
|
}
|
|
1215
1831
|
}
|
|
@@ -1223,7 +1839,7 @@ function PremoveLayerInner({ model, orientation, pieces, from, to }) {
|
|
|
1223
1839
|
top: `${target.y}%`,
|
|
1224
1840
|
width: "12.5%",
|
|
1225
1841
|
height: "12.5%",
|
|
1226
|
-
background:
|
|
1842
|
+
background: chunkN4WTPXFC_cjs.DEFAULT_PREMOVE_TINT
|
|
1227
1843
|
}
|
|
1228
1844
|
}
|
|
1229
1845
|
),
|
|
@@ -1258,20 +1874,20 @@ function positionOf4(index, orientation) {
|
|
|
1258
1874
|
return { x: col * 12.5, y: row * 12.5 };
|
|
1259
1875
|
}
|
|
1260
1876
|
var CHOICE_ORDER = [
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1877
|
+
chunkFUP2LDMO_cjs.PieceType.Queen,
|
|
1878
|
+
chunkFUP2LDMO_cjs.PieceType.Knight,
|
|
1879
|
+
chunkFUP2LDMO_cjs.PieceType.Rook,
|
|
1880
|
+
chunkFUP2LDMO_cjs.PieceType.Bishop
|
|
1265
1881
|
];
|
|
1266
1882
|
var SHORTCUTS = {
|
|
1267
|
-
q:
|
|
1268
|
-
r:
|
|
1269
|
-
b:
|
|
1270
|
-
n:
|
|
1271
|
-
Q:
|
|
1272
|
-
R:
|
|
1273
|
-
B:
|
|
1274
|
-
N:
|
|
1883
|
+
q: chunkFUP2LDMO_cjs.PieceType.Queen,
|
|
1884
|
+
r: chunkFUP2LDMO_cjs.PieceType.Rook,
|
|
1885
|
+
b: chunkFUP2LDMO_cjs.PieceType.Bishop,
|
|
1886
|
+
n: chunkFUP2LDMO_cjs.PieceType.Knight,
|
|
1887
|
+
Q: chunkFUP2LDMO_cjs.PieceType.Queen,
|
|
1888
|
+
R: chunkFUP2LDMO_cjs.PieceType.Rook,
|
|
1889
|
+
B: chunkFUP2LDMO_cjs.PieceType.Bishop,
|
|
1890
|
+
N: chunkFUP2LDMO_cjs.PieceType.Knight
|
|
1275
1891
|
};
|
|
1276
1892
|
function PromotionOverlay({
|
|
1277
1893
|
from: _from,
|
|
@@ -1289,7 +1905,7 @@ function PromotionOverlay({
|
|
|
1289
1905
|
[getPromotionPieceAriaLabel, color]
|
|
1290
1906
|
);
|
|
1291
1907
|
const [activeAnnouncement, setActiveAnnouncement] = react.useState(
|
|
1292
|
-
() => getLabel(CHOICE_ORDER[0] ??
|
|
1908
|
+
() => getLabel(CHOICE_ORDER[0] ?? chunkFUP2LDMO_cjs.PieceType.Queen)
|
|
1293
1909
|
);
|
|
1294
1910
|
react.useEffect(() => {
|
|
1295
1911
|
buttonRefs.current[0]?.focus();
|
|
@@ -1371,7 +1987,7 @@ function PromotionOverlay({
|
|
|
1371
1987
|
{
|
|
1372
1988
|
role: "dialog",
|
|
1373
1989
|
"aria-modal": "true",
|
|
1374
|
-
"aria-label": `Choose promotion piece at ${
|
|
1990
|
+
"aria-label": `Choose promotion piece at ${algebraicOf5(to)}`,
|
|
1375
1991
|
onClick: (e) => e.stopPropagation(),
|
|
1376
1992
|
style: {
|
|
1377
1993
|
position: "absolute",
|
|
@@ -1387,7 +2003,7 @@ function PromotionOverlay({
|
|
|
1387
2003
|
overflow: "hidden"
|
|
1388
2004
|
},
|
|
1389
2005
|
children: CHOICE_ORDER.map((piece, index) => {
|
|
1390
|
-
const cell =
|
|
2006
|
+
const cell = chunkFUP2LDMO_cjs.encodeBoardCell(color, piece);
|
|
1391
2007
|
const label = getLabel(piece);
|
|
1392
2008
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1393
2009
|
"button",
|
|
@@ -1439,19 +2055,19 @@ var srOnlyStyle2 = {
|
|
|
1439
2055
|
};
|
|
1440
2056
|
function pieceName2(t) {
|
|
1441
2057
|
switch (t) {
|
|
1442
|
-
case
|
|
2058
|
+
case chunkFUP2LDMO_cjs.PieceType.Queen:
|
|
1443
2059
|
return "Queen";
|
|
1444
|
-
case
|
|
2060
|
+
case chunkFUP2LDMO_cjs.PieceType.Rook:
|
|
1445
2061
|
return "Rook";
|
|
1446
|
-
case
|
|
2062
|
+
case chunkFUP2LDMO_cjs.PieceType.Bishop:
|
|
1447
2063
|
return "Bishop";
|
|
1448
|
-
case
|
|
2064
|
+
case chunkFUP2LDMO_cjs.PieceType.Knight:
|
|
1449
2065
|
return "Knight";
|
|
1450
2066
|
default:
|
|
1451
2067
|
return "Piece";
|
|
1452
2068
|
}
|
|
1453
2069
|
}
|
|
1454
|
-
function
|
|
2070
|
+
function algebraicOf5(index) {
|
|
1455
2071
|
const file = index & 7;
|
|
1456
2072
|
const rank = index >> 3;
|
|
1457
2073
|
return `${String.fromCharCode(97 + file)}${rank + 1}`;
|
|
@@ -1467,13 +2083,13 @@ function StaticPieceLayer({ board, orientation, pieces }) {
|
|
|
1467
2083
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1468
2084
|
"div",
|
|
1469
2085
|
{
|
|
1470
|
-
"data-piece-square":
|
|
2086
|
+
"data-piece-square": algebraicOf(index),
|
|
1471
2087
|
"data-piece-cell": cell,
|
|
1472
2088
|
style: {
|
|
1473
2089
|
...SLOT_BASE_STYLE,
|
|
1474
2090
|
gridColumnStart: col,
|
|
1475
2091
|
gridRowStart: row,
|
|
1476
|
-
filter: `var(${cell <= 6 ?
|
|
2092
|
+
filter: `var(${cell <= 6 ? chunkN4WTPXFC_cjs.CSS_VARS.PIECE_FILTER_WHITE : chunkN4WTPXFC_cjs.CSS_VARS.PIECE_FILTER_BLACK}, none)`
|
|
1477
2093
|
},
|
|
1478
2094
|
children: pieces({ cell, square: index })
|
|
1479
2095
|
},
|
|
@@ -1485,7 +2101,7 @@ function StaticPieceLayer({ board, orientation, pieces }) {
|
|
|
1485
2101
|
}
|
|
1486
2102
|
var DEFAULT_DURATION_MS = 60;
|
|
1487
2103
|
var DEFAULT_EASING = "cubic-bezier(0.22, 0.61, 0.36, 1)";
|
|
1488
|
-
function
|
|
2104
|
+
function algebraicOf6(index) {
|
|
1489
2105
|
const file = index & 7;
|
|
1490
2106
|
const rank = index >> 3;
|
|
1491
2107
|
return `${String.fromCharCode(97 + file)}${rank + 1}`;
|
|
@@ -1533,7 +2149,7 @@ function runAnimations(descriptors, container, orientation, duration, easing) {
|
|
|
1533
2149
|
case "en-passant":
|
|
1534
2150
|
case "promotion": {
|
|
1535
2151
|
const toEl = container.querySelector(
|
|
1536
|
-
`[data-piece-square="${
|
|
2152
|
+
`[data-piece-square="${algebraicOf6(d.to)}"]`
|
|
1537
2153
|
);
|
|
1538
2154
|
if (toEl === null) break;
|
|
1539
2155
|
const { dx, dy } = deltaFromTo(d.from, d.to, sqSize, orientation);
|
|
@@ -1542,10 +2158,10 @@ function runAnimations(descriptors, container, orientation, duration, easing) {
|
|
|
1542
2158
|
}
|
|
1543
2159
|
case "castle": {
|
|
1544
2160
|
const kingEl = container.querySelector(
|
|
1545
|
-
`[data-piece-square="${
|
|
2161
|
+
`[data-piece-square="${algebraicOf6(d.kingTo)}"]`
|
|
1546
2162
|
);
|
|
1547
2163
|
const rookEl = container.querySelector(
|
|
1548
|
-
`[data-piece-square="${
|
|
2164
|
+
`[data-piece-square="${algebraicOf6(d.rookTo)}"]`
|
|
1549
2165
|
);
|
|
1550
2166
|
if (kingEl !== null) {
|
|
1551
2167
|
const { dx, dy } = deltaFromTo(d.kingFrom, d.kingTo, sqSize, orientation);
|
|
@@ -1589,39 +2205,6 @@ function AnimationRunner({
|
|
|
1589
2205
|
}, [historyPly, model, containerRef, orientation, duration, easing, skipNextRef]);
|
|
1590
2206
|
return null;
|
|
1591
2207
|
}
|
|
1592
|
-
|
|
1593
|
-
// src/lib/geometry.ts
|
|
1594
|
-
function getSquareAtPoint(container, clientX, clientY, orientation) {
|
|
1595
|
-
const rect = container.getBoundingClientRect();
|
|
1596
|
-
const relX = clientX - rect.left;
|
|
1597
|
-
const relY = clientY - rect.top;
|
|
1598
|
-
if (relX < 0 || relY < 0 || relX >= rect.width || relY >= rect.height) return null;
|
|
1599
|
-
const col = Math.floor(relX / rect.width * 8);
|
|
1600
|
-
const row = Math.floor(relY / rect.height * 8);
|
|
1601
|
-
const file = orientation === "white" ? col : 7 - col;
|
|
1602
|
-
const rank = orientation === "white" ? 7 - row : row;
|
|
1603
|
-
return rank * 8 + file;
|
|
1604
|
-
}
|
|
1605
|
-
function getPointAtSquareCentre(container, square, orientation) {
|
|
1606
|
-
const rect = container.getBoundingClientRect();
|
|
1607
|
-
const sqW = rect.width / 8;
|
|
1608
|
-
const sqH = rect.height / 8;
|
|
1609
|
-
const file = square & 7;
|
|
1610
|
-
const rank = square >> 3;
|
|
1611
|
-
const col = orientation === "white" ? file : 7 - file;
|
|
1612
|
-
const row = orientation === "white" ? 7 - rank : rank;
|
|
1613
|
-
return {
|
|
1614
|
-
x: rect.left + sqW * col + sqW / 2,
|
|
1615
|
-
y: rect.top + sqH * row + sqH / 2
|
|
1616
|
-
};
|
|
1617
|
-
}
|
|
1618
|
-
function algebraicOf6(square) {
|
|
1619
|
-
const file = square & 7;
|
|
1620
|
-
const rank = square >> 3;
|
|
1621
|
-
return `${String.fromCharCode(97 + file)}${rank + 1}`;
|
|
1622
|
-
}
|
|
1623
|
-
|
|
1624
|
-
// src/hooks/use-arrow-gesture.ts
|
|
1625
2208
|
function colorForModifiers(e, palette) {
|
|
1626
2209
|
if (e.shiftKey) return palette.shift;
|
|
1627
2210
|
if (e.altKey) return palette.alt;
|
|
@@ -1725,7 +2308,7 @@ function useArrowGesture(options) {
|
|
|
1725
2308
|
function wouldPromote(fromCell, toIndex) {
|
|
1726
2309
|
if (fromCell === 0) return false;
|
|
1727
2310
|
const pieceType = (fromCell - 1) % 6;
|
|
1728
|
-
if (pieceType !==
|
|
2311
|
+
if (pieceType !== chunkFUP2LDMO_cjs.PieceType.Pawn) return false;
|
|
1729
2312
|
const toRank = toIndex >> 3;
|
|
1730
2313
|
return toRank === 0 || toRank === 7;
|
|
1731
2314
|
}
|
|
@@ -1736,7 +2319,7 @@ function useClickToMove(model, onMove, onPromotionNeeded, enabled = true) {
|
|
|
1736
2319
|
if (model === null) return;
|
|
1737
2320
|
const snap = model.getSnapshot();
|
|
1738
2321
|
const cell = snap.board[index] ?? 0;
|
|
1739
|
-
const pieceColour = cell === 0 ? -1 : cell > 6 ?
|
|
2322
|
+
const pieceColour = cell === 0 ? -1 : cell > 6 ? chunkFUP2LDMO_cjs.Color.Black : chunkFUP2LDMO_cjs.Color.White;
|
|
1740
2323
|
if (snap.selected === null) {
|
|
1741
2324
|
if (pieceColour === snap.turn) model.selectSquare(index);
|
|
1742
2325
|
return;
|
|
@@ -1752,7 +2335,7 @@ function useClickToMove(model, onMove, onPromotionNeeded, enabled = true) {
|
|
|
1752
2335
|
onPromotionNeeded(snap.selected, index);
|
|
1753
2336
|
return;
|
|
1754
2337
|
}
|
|
1755
|
-
const played2 = model.tryMove(snap.selected, index,
|
|
2338
|
+
const played2 = model.tryMove(snap.selected, index, chunkFUP2LDMO_cjs.PieceType.Queen);
|
|
1756
2339
|
if (played2 !== null && onMove !== void 0) onMove(played2);
|
|
1757
2340
|
return;
|
|
1758
2341
|
}
|
|
@@ -1864,7 +2447,7 @@ function useCursorController(model, containerRef, allowDrag, allowPremove) {
|
|
|
1864
2447
|
};
|
|
1865
2448
|
}, [model, containerRef, allowDrag, allowPremove]);
|
|
1866
2449
|
}
|
|
1867
|
-
var GHOST_OPACITY_VAR =
|
|
2450
|
+
var GHOST_OPACITY_VAR = chunkN4WTPXFC_cjs.CSS_VARS.DRAG_GHOST_OPACITY;
|
|
1868
2451
|
function useDrag(options) {
|
|
1869
2452
|
const {
|
|
1870
2453
|
game,
|
|
@@ -1886,7 +2469,7 @@ function useDrag(options) {
|
|
|
1886
2469
|
if (!enabled) return;
|
|
1887
2470
|
const container = containerRef.current;
|
|
1888
2471
|
if (container === null || game === null) return;
|
|
1889
|
-
const controller =
|
|
2472
|
+
const controller = chunkFUP2LDMO_cjs.createDragController(
|
|
1890
2473
|
activationDistance === void 0 ? {} : { activationDistance }
|
|
1891
2474
|
);
|
|
1892
2475
|
let originEl = null;
|
|
@@ -1936,7 +2519,7 @@ function useDrag(options) {
|
|
|
1936
2519
|
controller.cancel();
|
|
1937
2520
|
return;
|
|
1938
2521
|
}
|
|
1939
|
-
const originLabel =
|
|
2522
|
+
const originLabel = algebraicOf2(evt.from);
|
|
1940
2523
|
originEl = container.querySelector(`[data-piece-square="${originLabel}"]`);
|
|
1941
2524
|
if (originEl !== null) {
|
|
1942
2525
|
originEl.style.opacity = `var(${GHOST_OPACITY_VAR}, 0.35)`;
|
|
@@ -2185,7 +2768,7 @@ function useLastMoveController(model, squareRefs, enabled) {
|
|
|
2185
2768
|
const lastMove = snap.lastMove;
|
|
2186
2769
|
let from = null;
|
|
2187
2770
|
let to = null;
|
|
2188
|
-
if (lastMove !== null) {
|
|
2771
|
+
if (lastMove !== null && !chunkFUP2LDMO_cjs.isNullMove(lastMove)) {
|
|
2189
2772
|
from = lastMove & 63;
|
|
2190
2773
|
to = lastMove >> 6 & 63;
|
|
2191
2774
|
}
|
|
@@ -2595,6 +3178,9 @@ var ILLEGAL_FLASH_HOLD_MS = 320;
|
|
|
2595
3178
|
var DEFAULT_POSITION_SYNC_DURATION_MS = 60;
|
|
2596
3179
|
var DEFAULT_POSITION_SYNC_EASING = "cubic-bezier(0.22, 0.61, 0.36, 1)";
|
|
2597
3180
|
var UCI_TRANSITION_RE = /^([a-h][1-8])([a-h][1-8])([nbrq])?$/i;
|
|
3181
|
+
function isNullTransition(transition) {
|
|
3182
|
+
return chunkFUP2LDMO_cjs.isNullMoveUci(transition.uci);
|
|
3183
|
+
}
|
|
2598
3184
|
function prefersReducedMotion3() {
|
|
2599
3185
|
if (typeof window === "undefined" || typeof window.matchMedia !== "function") {
|
|
2600
3186
|
return false;
|
|
@@ -2642,6 +3228,7 @@ function castleRookTransition(from, to) {
|
|
|
2642
3228
|
};
|
|
2643
3229
|
}
|
|
2644
3230
|
function transitionSquares(transition) {
|
|
3231
|
+
if (isNullTransition(transition)) return [];
|
|
2645
3232
|
const parsed = UCI_TRANSITION_RE.exec(transition.uci.trim().toLowerCase());
|
|
2646
3233
|
if (parsed === null) return [];
|
|
2647
3234
|
const moveFrom = parsed[1] ?? "";
|
|
@@ -2652,6 +3239,7 @@ function transitionSquares(transition) {
|
|
|
2652
3239
|
return transition.direction === "forward" ? forward : forward.map((item) => ({ from: item.to, to: item.from }));
|
|
2653
3240
|
}
|
|
2654
3241
|
function parseTransitionMove(transition) {
|
|
3242
|
+
if (isNullTransition(transition)) return null;
|
|
2655
3243
|
const parsed = UCI_TRANSITION_RE.exec(transition.uci.trim().toLowerCase());
|
|
2656
3244
|
if (parsed === null) return null;
|
|
2657
3245
|
const from = parsed[1];
|
|
@@ -2664,7 +3252,7 @@ function parseTransitionMove(transition) {
|
|
|
2664
3252
|
};
|
|
2665
3253
|
}
|
|
2666
3254
|
function isPawn(cell) {
|
|
2667
|
-
return !
|
|
3255
|
+
return !chunkFUP2LDMO_cjs.isEmptyCell(cell) && chunkFUP2LDMO_cjs.pieceTypeOf(cell) === 0;
|
|
2668
3256
|
}
|
|
2669
3257
|
function controlledFeedbackDescriptors(transition, previousBoard, nextBoard) {
|
|
2670
3258
|
if (transition === null || transition === void 0) return null;
|
|
@@ -2673,25 +3261,25 @@ function controlledFeedbackDescriptors(transition, previousBoard, nextBoard) {
|
|
|
2673
3261
|
const before = transition.direction === "forward" ? previousBoard : nextBoard;
|
|
2674
3262
|
const after = transition.direction === "forward" ? nextBoard : previousBoard;
|
|
2675
3263
|
const movingPiece = before[parsed.from] ?? 0;
|
|
2676
|
-
if (
|
|
3264
|
+
if (chunkFUP2LDMO_cjs.isEmptyCell(movingPiece)) return null;
|
|
2677
3265
|
const fromFile = parsed.from & 7;
|
|
2678
3266
|
const toFile = parsed.to & 7;
|
|
2679
3267
|
const targetBefore = before[parsed.to] ?? 0;
|
|
2680
3268
|
const targetAfter = after[parsed.to] ?? 0;
|
|
2681
|
-
if (
|
|
3269
|
+
if (chunkFUP2LDMO_cjs.pieceTypeOf(movingPiece) === 5 && Math.abs(toFile - fromFile) === 2) {
|
|
2682
3270
|
return [{ kind: "castle" }];
|
|
2683
3271
|
}
|
|
2684
|
-
if (parsed.promotion !== null || isPawn(movingPiece) && (parsed.to >> 3 === 0 || parsed.to >> 3 === 7) && !
|
|
3272
|
+
if (parsed.promotion !== null || isPawn(movingPiece) && (parsed.to >> 3 === 0 || parsed.to >> 3 === 7) && !chunkFUP2LDMO_cjs.isEmptyCell(targetAfter) && chunkFUP2LDMO_cjs.pieceTypeOf(targetAfter) !== 0) {
|
|
2685
3273
|
return [{ kind: "promotion" }];
|
|
2686
3274
|
}
|
|
2687
|
-
if (!
|
|
3275
|
+
if (!chunkFUP2LDMO_cjs.isEmptyCell(targetBefore) && chunkFUP2LDMO_cjs.colorOf(targetBefore) !== chunkFUP2LDMO_cjs.colorOf(movingPiece)) {
|
|
2688
3276
|
return [{ kind: "capture" }];
|
|
2689
3277
|
}
|
|
2690
|
-
if (isPawn(movingPiece) && fromFile !== toFile &&
|
|
3278
|
+
if (isPawn(movingPiece) && fromFile !== toFile && chunkFUP2LDMO_cjs.isEmptyCell(targetBefore)) {
|
|
2691
3279
|
const capturedSquare = parsed.from & -8 | toFile;
|
|
2692
3280
|
const capturedBefore = before[capturedSquare] ?? 0;
|
|
2693
3281
|
const capturedAfter = after[capturedSquare] ?? 0;
|
|
2694
|
-
if (!
|
|
3282
|
+
if (!chunkFUP2LDMO_cjs.isEmptyCell(capturedBefore) && chunkFUP2LDMO_cjs.colorOf(capturedBefore) !== chunkFUP2LDMO_cjs.colorOf(movingPiece) && chunkFUP2LDMO_cjs.isEmptyCell(capturedAfter)) {
|
|
2695
3283
|
return [{ kind: "en-passant" }];
|
|
2696
3284
|
}
|
|
2697
3285
|
}
|
|
@@ -2759,8 +3347,8 @@ function Chessboard(props) {
|
|
|
2759
3347
|
managedArrows,
|
|
2760
3348
|
preserveUserArrowsOnPositionSync,
|
|
2761
3349
|
orientation = "white",
|
|
2762
|
-
theme =
|
|
2763
|
-
pieces =
|
|
3350
|
+
theme = chunkN4WTPXFC_cjs.defaultTheme,
|
|
3351
|
+
pieces = chunkN4WTPXFC_cjs.defaultPieces,
|
|
2764
3352
|
showCoordinates = true,
|
|
2765
3353
|
ranksPosition = "left",
|
|
2766
3354
|
showLegalTargets = "rings",
|
|
@@ -2799,7 +3387,7 @@ function Chessboard(props) {
|
|
|
2799
3387
|
const fallbackBoard = react.useMemo(() => {
|
|
2800
3388
|
if (fallbackFen === void 0 || fallbackFen === "") return null;
|
|
2801
3389
|
try {
|
|
2802
|
-
return
|
|
3390
|
+
return chunkN4WTPXFC_cjs.parseFenPlacement(fallbackFen);
|
|
2803
3391
|
} catch {
|
|
2804
3392
|
return null;
|
|
2805
3393
|
}
|
|
@@ -2877,10 +3465,10 @@ function Chessboard(props) {
|
|
|
2877
3465
|
]);
|
|
2878
3466
|
const palette = react.useMemo(() => {
|
|
2879
3467
|
const merged = {
|
|
2880
|
-
default:
|
|
2881
|
-
shift:
|
|
2882
|
-
alt:
|
|
2883
|
-
ctrl:
|
|
3468
|
+
default: chunkN4WTPXFC_cjs.defaultArrowColors.default,
|
|
3469
|
+
shift: chunkN4WTPXFC_cjs.defaultArrowColors.shift,
|
|
3470
|
+
alt: chunkN4WTPXFC_cjs.defaultArrowColors.alt,
|
|
3471
|
+
ctrl: chunkN4WTPXFC_cjs.defaultArrowColors.ctrl
|
|
2884
3472
|
};
|
|
2885
3473
|
if (arrowColors !== void 0) {
|
|
2886
3474
|
for (const k in arrowColors) {
|
|
@@ -3198,15 +3786,15 @@ function useChessGame(options = {}) {
|
|
|
3198
3786
|
const { fen, ...modelOptions } = options;
|
|
3199
3787
|
const [initialModelOptions] = react.useState(() => modelOptions);
|
|
3200
3788
|
const [model, setModel] = react.useState(() => {
|
|
3201
|
-
const adapter =
|
|
3202
|
-
return
|
|
3789
|
+
const adapter = chunkFUP2LDMO_cjs.createGigachessAdapter(fen);
|
|
3790
|
+
return chunkFUP2LDMO_cjs.createBoardModel(adapter, modelOptions);
|
|
3203
3791
|
});
|
|
3204
3792
|
const prevFenRef = react.useRef(fen);
|
|
3205
3793
|
react.useEffect(() => {
|
|
3206
3794
|
if (prevFenRef.current !== fen) {
|
|
3207
3795
|
prevFenRef.current = fen;
|
|
3208
|
-
const adapter =
|
|
3209
|
-
const nextModel =
|
|
3796
|
+
const adapter = chunkFUP2LDMO_cjs.createGigachessAdapter(fen);
|
|
3797
|
+
const nextModel = chunkFUP2LDMO_cjs.createBoardModel(adapter, initialModelOptions);
|
|
3210
3798
|
setModel((prev) => {
|
|
3211
3799
|
prev.dispose();
|
|
3212
3800
|
return nextModel;
|
|
@@ -3222,68 +3810,100 @@ function useChessGame(options = {}) {
|
|
|
3222
3810
|
}
|
|
3223
3811
|
|
|
3224
3812
|
// src/index.ts
|
|
3225
|
-
var PACKAGE_VERSION = "1.
|
|
3813
|
+
var PACKAGE_VERSION = "1.5.0";
|
|
3226
3814
|
|
|
3227
3815
|
Object.defineProperty(exports, "Color", {
|
|
3228
3816
|
enumerable: true,
|
|
3229
|
-
get: function () { return
|
|
3817
|
+
get: function () { return chunkFUP2LDMO_cjs.Color; }
|
|
3818
|
+
});
|
|
3819
|
+
Object.defineProperty(exports, "NULL_MOVE_SAN", {
|
|
3820
|
+
enumerable: true,
|
|
3821
|
+
get: function () { return chunkFUP2LDMO_cjs.NULL_MOVE_SAN; }
|
|
3822
|
+
});
|
|
3823
|
+
Object.defineProperty(exports, "NULL_MOVE_SANS", {
|
|
3824
|
+
enumerable: true,
|
|
3825
|
+
get: function () { return chunkFUP2LDMO_cjs.NULL_MOVE_SANS; }
|
|
3826
|
+
});
|
|
3827
|
+
Object.defineProperty(exports, "NULL_MOVE_UCI", {
|
|
3828
|
+
enumerable: true,
|
|
3829
|
+
get: function () { return chunkFUP2LDMO_cjs.NULL_MOVE_UCI; }
|
|
3830
|
+
});
|
|
3831
|
+
Object.defineProperty(exports, "NULL_MOVE_WORD", {
|
|
3832
|
+
enumerable: true,
|
|
3833
|
+
get: function () { return chunkFUP2LDMO_cjs.NULL_MOVE_WORD; }
|
|
3230
3834
|
});
|
|
3231
3835
|
Object.defineProperty(exports, "PieceType", {
|
|
3232
3836
|
enumerable: true,
|
|
3233
|
-
get: function () { return
|
|
3837
|
+
get: function () { return chunkFUP2LDMO_cjs.PieceType; }
|
|
3234
3838
|
});
|
|
3235
3839
|
Object.defineProperty(exports, "createBoardModel", {
|
|
3236
3840
|
enumerable: true,
|
|
3237
|
-
get: function () { return
|
|
3841
|
+
get: function () { return chunkFUP2LDMO_cjs.createBoardModel; }
|
|
3238
3842
|
});
|
|
3239
3843
|
Object.defineProperty(exports, "createGigachessAdapter", {
|
|
3240
3844
|
enumerable: true,
|
|
3241
|
-
get: function () { return
|
|
3845
|
+
get: function () { return chunkFUP2LDMO_cjs.createGigachessAdapter; }
|
|
3846
|
+
});
|
|
3847
|
+
Object.defineProperty(exports, "isNullMove", {
|
|
3848
|
+
enumerable: true,
|
|
3849
|
+
get: function () { return chunkFUP2LDMO_cjs.isNullMove; }
|
|
3850
|
+
});
|
|
3851
|
+
Object.defineProperty(exports, "isNullMoveSan", {
|
|
3852
|
+
enumerable: true,
|
|
3853
|
+
get: function () { return chunkFUP2LDMO_cjs.isNullMoveSan; }
|
|
3854
|
+
});
|
|
3855
|
+
Object.defineProperty(exports, "isNullMoveUci", {
|
|
3856
|
+
enumerable: true,
|
|
3857
|
+
get: function () { return chunkFUP2LDMO_cjs.isNullMoveUci; }
|
|
3242
3858
|
});
|
|
3243
3859
|
Object.defineProperty(exports, "packMove", {
|
|
3244
3860
|
enumerable: true,
|
|
3245
|
-
get: function () { return
|
|
3861
|
+
get: function () { return chunkFUP2LDMO_cjs.packMove; }
|
|
3246
3862
|
});
|
|
3247
3863
|
Object.defineProperty(exports, "preloadGigachessAdapter", {
|
|
3248
3864
|
enumerable: true,
|
|
3249
|
-
get: function () { return
|
|
3865
|
+
get: function () { return chunkFUP2LDMO_cjs.preloadGigachessAdapter; }
|
|
3250
3866
|
});
|
|
3251
3867
|
Object.defineProperty(exports, "unpackMove", {
|
|
3252
3868
|
enumerable: true,
|
|
3253
|
-
get: function () { return
|
|
3869
|
+
get: function () { return chunkFUP2LDMO_cjs.unpackMove; }
|
|
3254
3870
|
});
|
|
3255
3871
|
Object.defineProperty(exports, "CSS_VARS", {
|
|
3256
3872
|
enumerable: true,
|
|
3257
|
-
get: function () { return
|
|
3873
|
+
get: function () { return chunkN4WTPXFC_cjs.CSS_VARS; }
|
|
3258
3874
|
});
|
|
3259
3875
|
Object.defineProperty(exports, "DEFAULT_ILLEGAL_FLASH_TINT", {
|
|
3260
3876
|
enumerable: true,
|
|
3261
|
-
get: function () { return
|
|
3877
|
+
get: function () { return chunkN4WTPXFC_cjs.DEFAULT_ILLEGAL_FLASH_TINT; }
|
|
3262
3878
|
});
|
|
3263
3879
|
Object.defineProperty(exports, "DEFAULT_PREMOVE_TINT", {
|
|
3264
3880
|
enumerable: true,
|
|
3265
|
-
get: function () { return
|
|
3881
|
+
get: function () { return chunkN4WTPXFC_cjs.DEFAULT_PREMOVE_TINT; }
|
|
3266
3882
|
});
|
|
3267
3883
|
Object.defineProperty(exports, "defaultArrowColors", {
|
|
3268
3884
|
enumerable: true,
|
|
3269
|
-
get: function () { return
|
|
3885
|
+
get: function () { return chunkN4WTPXFC_cjs.defaultArrowColors; }
|
|
3270
3886
|
});
|
|
3271
3887
|
Object.defineProperty(exports, "defaultPieces", {
|
|
3272
3888
|
enumerable: true,
|
|
3273
|
-
get: function () { return
|
|
3889
|
+
get: function () { return chunkN4WTPXFC_cjs.defaultPieces; }
|
|
3274
3890
|
});
|
|
3275
3891
|
Object.defineProperty(exports, "defaultTheme", {
|
|
3276
3892
|
enumerable: true,
|
|
3277
|
-
get: function () { return
|
|
3893
|
+
get: function () { return chunkN4WTPXFC_cjs.defaultTheme; }
|
|
3278
3894
|
});
|
|
3279
3895
|
exports.AnimationRunner = AnimationRunner;
|
|
3896
|
+
exports.BoardEditor = BoardEditor;
|
|
3280
3897
|
exports.Chessboard = Chessboard;
|
|
3281
3898
|
exports.DEFAULT_MOVE_HAPTIC_PATTERNS = DEFAULT_MOVE_HAPTIC_PATTERNS;
|
|
3282
3899
|
exports.DEFAULT_MOVE_SOUND_SOURCES = DEFAULT_MOVE_SOUND_SOURCES;
|
|
3283
3900
|
exports.PACKAGE_VERSION = PACKAGE_VERSION;
|
|
3901
|
+
exports.algebraicOf = algebraicOf2;
|
|
3284
3902
|
exports.classifyMoveFeedback = classifyMoveFeedback;
|
|
3903
|
+
exports.formatFenPlacement = formatFenPlacement;
|
|
3285
3904
|
exports.getPointAtSquareCentre = getPointAtSquareCentre;
|
|
3286
3905
|
exports.getSquareAtPoint = getSquareAtPoint;
|
|
3906
|
+
exports.squareOf = squareOf;
|
|
3287
3907
|
exports.triggerHaptic = triggerHaptic;
|
|
3288
3908
|
exports.triggerMoveHaptic = triggerMoveHaptic;
|
|
3289
3909
|
exports.useArrowGesture = useArrowGesture;
|