hyperchess-board-ui 0.1.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/LICENSE +674 -0
- package/README.md +40 -0
- package/dist/React/Board.d.ts +9 -0
- package/dist/React/Board.d.ts.map +1 -0
- package/dist/React/Board.js +50 -0
- package/dist/React/Board.js.map +1 -0
- package/dist/React/useBoardState.d.ts +26 -0
- package/dist/React/useBoardState.d.ts.map +1 -0
- package/dist/React/useBoardState.js +129 -0
- package/dist/React/useBoardState.js.map +1 -0
- package/dist/Vue/useBoardState.d.ts +105 -0
- package/dist/Vue/useBoardState.d.ts.map +1 -0
- package/dist/Vue/useBoardState.js +116 -0
- package/dist/Vue/useBoardState.js.map +1 -0
- package/dist/types/props.d.ts +92 -0
- package/dist/types/props.d.ts.map +1 -0
- package/dist/types/props.js +7 -0
- package/dist/types/props.js.map +1 -0
- package/dist/web-component/hyperchess-board.d.ts +49 -0
- package/dist/web-component/hyperchess-board.d.ts.map +1 -0
- package/dist/web-component/hyperchess-board.js +102 -0
- package/dist/web-component/hyperchess-board.js.map +1 -0
- package/package.json +81 -0
package/README.md
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# hyperchess-board-ui
|
|
2
|
+
|
|
3
|
+
2D board UI for [HyperChess](https://github.com/KyrpyDev/hyperchess-core) — the 12×12 chess
|
|
4
|
+
variant with Eagle and Hawk pieces. One package, three framework targets:
|
|
5
|
+
|
|
6
|
+
```js
|
|
7
|
+
import Board, { useBoardState } from 'hyperchess-board-ui/react'; // React ≥ 18
|
|
8
|
+
import { Board } from 'hyperchess-board-ui/vue'; // Vue ≥ 3
|
|
9
|
+
import 'hyperchess-board-ui/web-component'; // <hyperchess-board-ui> element
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
React and Vue are **optional peer dependencies** — install only the one you use. The web
|
|
13
|
+
component target has no framework dependency at all:
|
|
14
|
+
|
|
15
|
+
```html
|
|
16
|
+
<script type="module">
|
|
17
|
+
import 'hyperchess-board-ui/web-component';
|
|
18
|
+
</script>
|
|
19
|
+
<hyperchess-board-ui></hyperchess-board-ui>
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Quick start (React)
|
|
23
|
+
|
|
24
|
+
```jsx
|
|
25
|
+
import Board, { useBoardState } from 'hyperchess-board-ui/react';
|
|
26
|
+
|
|
27
|
+
function App() {
|
|
28
|
+
const { board, applyMove } = useBoardState(); // standard 12×12 start
|
|
29
|
+
return <Board board={board} onMove={applyMove} />;
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Theming comes from [`hyperchess-theme`](https://www.npmjs.com/package/hyperchess-theme); game
|
|
34
|
+
logic from [`hyperchess-core`](https://www.npmjs.com/package/hyperchess-core). To add the full
|
|
35
|
+
Rust engine (best-move search) use
|
|
36
|
+
[`hyperchess-wasm`](https://www.npmjs.com/package/hyperchess-wasm).
|
|
37
|
+
|
|
38
|
+
Part of the [HyperChess Core](https://github.com/KyrpyDev/hyperchess-core) monorepo —
|
|
39
|
+
see the repository README for the full stack, contributing guide, and license
|
|
40
|
+
(GPL-3.0-or-later).
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { BoardProps } from '../types/props';
|
|
3
|
+
/**
|
|
4
|
+
* React board component
|
|
5
|
+
* Renders interactive 2D HyperChess board
|
|
6
|
+
*/
|
|
7
|
+
export declare const Board: React.FC<BoardProps>;
|
|
8
|
+
export default Board;
|
|
9
|
+
//# sourceMappingURL=Board.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Board.d.ts","sourceRoot":"","sources":["../../src/React/Board.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAgC,MAAM,OAAO,CAAC;AAErD,OAAO,EAAE,UAAU,EAAkB,MAAM,gBAAgB,CAAC;AAG5D;;;GAGG;AACH,eAAO,MAAM,KAAK,EAAE,KAAK,CAAC,EAAE,CAAC,UAAU,CA+EtC,CAAC;AAEF,eAAe,KAAK,CAAC"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useCallback } from 'react';
|
|
3
|
+
import { useBoardState } from './useBoardState';
|
|
4
|
+
/**
|
|
5
|
+
* React board component
|
|
6
|
+
* Renders interactive 2D HyperChess board
|
|
7
|
+
*/
|
|
8
|
+
export const Board = ({ hfen, theme = 'modern', onMove, onSquareClick, enableDragDrop = true, showCoordinates = true, flipBoard = false, highlightLastMove = true, highlightLegalMoves = true, mode = 'play', disabled = false, className, pieceStyle = 'unicode', animationSpeed = 300, size = 'responsive', }) => {
|
|
9
|
+
const { board, selection, makeMove, selectSquare } = useBoardState(hfen);
|
|
10
|
+
const [isDragging, setIsDragging] = useState(false);
|
|
11
|
+
const [dragFrom, setDragFrom] = useState(null);
|
|
12
|
+
const handleSquareClick = useCallback((square) => {
|
|
13
|
+
if (disabled || mode === 'view')
|
|
14
|
+
return;
|
|
15
|
+
selectSquare(square);
|
|
16
|
+
onSquareClick?.(square);
|
|
17
|
+
}, [disabled, mode, selectSquare, onSquareClick]);
|
|
18
|
+
const handleDragStart = useCallback((square) => {
|
|
19
|
+
if (disabled || !enableDragDrop)
|
|
20
|
+
return;
|
|
21
|
+
setIsDragging(true);
|
|
22
|
+
setDragFrom(square);
|
|
23
|
+
}, [disabled, enableDragDrop]);
|
|
24
|
+
const handleDragEnd = useCallback(() => {
|
|
25
|
+
setIsDragging(false);
|
|
26
|
+
}, []);
|
|
27
|
+
const handleDrop = useCallback((to) => {
|
|
28
|
+
if (!dragFrom || !board)
|
|
29
|
+
return;
|
|
30
|
+
const move = { from: dragFrom, to };
|
|
31
|
+
const success = makeMove(move);
|
|
32
|
+
if (success) {
|
|
33
|
+
onMove?.(move);
|
|
34
|
+
}
|
|
35
|
+
setDragFrom(null);
|
|
36
|
+
handleDragEnd();
|
|
37
|
+
}, [dragFrom, board, makeMove, onMove, handleDragEnd]);
|
|
38
|
+
if (!board) {
|
|
39
|
+
return _jsx("div", { className: `hyperchess-board-ui ${className || ''}`, children: "Loading..." });
|
|
40
|
+
}
|
|
41
|
+
return (_jsx("div", { className: `hyperchess-board-ui hyperchess-board-ui-${theme} ${className || ''}`, style: {
|
|
42
|
+
display: 'grid',
|
|
43
|
+
gridTemplateColumns: 'repeat(12, 1fr)',
|
|
44
|
+
gap: '0',
|
|
45
|
+
aspectRatio: '1',
|
|
46
|
+
width: size === 'responsive' ? '100%' : `${size}px`,
|
|
47
|
+
}, children: _jsx("div", { style: { gridColumn: '1 / -1', padding: '20px', textAlign: 'center' }, children: "Board rendering coming in Phase 3.0.4" }) }));
|
|
48
|
+
};
|
|
49
|
+
export default Board;
|
|
50
|
+
//# sourceMappingURL=Board.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Board.js","sourceRoot":"","sources":["../../src/React/Board.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Board as BoardType, Move, HfenString } from 'hyperchess-core';
|
|
2
|
+
import { SelectionState } from '../types/props';
|
|
3
|
+
/**
|
|
4
|
+
* React hook owning the board position and the user's click-to-move selection.
|
|
5
|
+
*
|
|
6
|
+
* `initialHfen` seeds the first render only; later changes to it are ignored,
|
|
7
|
+
* so remount the component (or key it) to load a different position. Note that
|
|
8
|
+
* `reset()` returns to the standard starting position rather than back to
|
|
9
|
+
* `initialHfen`.
|
|
10
|
+
*
|
|
11
|
+
* @param initialHfen - Starting position as an HFEN string or a prebuilt
|
|
12
|
+
* `Board`. A `Board` is adopted by reference, not copied. Omitted means the
|
|
13
|
+
* standard opening position.
|
|
14
|
+
* @returns The current `board`, the transient `selection` state, the memoised
|
|
15
|
+
* `legalMoves` for the side to move, and the `selectSquare` / `makeMove` /
|
|
16
|
+
* `reset` actions.
|
|
17
|
+
*/
|
|
18
|
+
export declare function useBoardState(initialHfen?: HfenString | BoardType): {
|
|
19
|
+
board: BoardType | null;
|
|
20
|
+
selection: SelectionState;
|
|
21
|
+
selectSquare: (square: number) => void;
|
|
22
|
+
makeMove: (move: Move) => boolean;
|
|
23
|
+
reset: () => void;
|
|
24
|
+
legalMoves: Move[];
|
|
25
|
+
};
|
|
26
|
+
//# sourceMappingURL=useBoardState.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useBoardState.d.ts","sourceRoot":"","sources":["../../src/React/useBoardState.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,IAAI,EAAE,UAAU,EAA8C,MAAM,iBAAiB,CAAC;AACnH,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAEhD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,aAAa,CAAC,WAAW,CAAC,EAAE,UAAU,GAAG,SAAS;;;2BAiCrD,MAAM;qBA8CR,IAAI;;;EAyCd"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
2
|
+
// HyperChess Core — hyperchess-board-ui
|
|
3
|
+
// File: packages/board/src/React/useBoardState.ts
|
|
4
|
+
// Version: 1.0.0
|
|
5
|
+
// Copyright (c) 2026 HyperChess Developer Team
|
|
6
|
+
import { useState, useCallback, useMemo } from 'react';
|
|
7
|
+
import { createBoard, applyMove, generateLegalMoves } from 'hyperchess-core';
|
|
8
|
+
/**
|
|
9
|
+
* React hook owning the board position and the user's click-to-move selection.
|
|
10
|
+
*
|
|
11
|
+
* `initialHfen` seeds the first render only; later changes to it are ignored,
|
|
12
|
+
* so remount the component (or key it) to load a different position. Note that
|
|
13
|
+
* `reset()` returns to the standard starting position rather than back to
|
|
14
|
+
* `initialHfen`.
|
|
15
|
+
*
|
|
16
|
+
* @param initialHfen - Starting position as an HFEN string or a prebuilt
|
|
17
|
+
* `Board`. A `Board` is adopted by reference, not copied. Omitted means the
|
|
18
|
+
* standard opening position.
|
|
19
|
+
* @returns The current `board`, the transient `selection` state, the memoised
|
|
20
|
+
* `legalMoves` for the side to move, and the `selectSquare` / `makeMove` /
|
|
21
|
+
* `reset` actions.
|
|
22
|
+
*/
|
|
23
|
+
export function useBoardState(initialHfen) {
|
|
24
|
+
const [board, setBoard] = useState(() => {
|
|
25
|
+
if (!initialHfen) {
|
|
26
|
+
return createBoard();
|
|
27
|
+
}
|
|
28
|
+
if (typeof initialHfen === 'string') {
|
|
29
|
+
return createBoard(initialHfen);
|
|
30
|
+
}
|
|
31
|
+
return initialHfen;
|
|
32
|
+
});
|
|
33
|
+
const [selection, setSelection] = useState({
|
|
34
|
+
selectedSquare: null,
|
|
35
|
+
legalMoves: [],
|
|
36
|
+
lastMove: null,
|
|
37
|
+
});
|
|
38
|
+
const legalMoves = useMemo(() => {
|
|
39
|
+
if (!board)
|
|
40
|
+
return [];
|
|
41
|
+
return generateLegalMoves(board);
|
|
42
|
+
}, [board]);
|
|
43
|
+
/**
|
|
44
|
+
* Handle a click on a square, driving the three-state selection cycle.
|
|
45
|
+
*
|
|
46
|
+
* Clicking one's own piece selects it (and re-selects when another own piece
|
|
47
|
+
* is clicked), clicking a highlighted destination plays the move, and any
|
|
48
|
+
* other click clears the selection. `lastMove` is deliberately preserved
|
|
49
|
+
* across a deselect so the last-move highlight does not flicker.
|
|
50
|
+
*
|
|
51
|
+
* @param square - Flat board index that was clicked.
|
|
52
|
+
*/
|
|
53
|
+
const selectSquare = useCallback((square) => {
|
|
54
|
+
if (!board)
|
|
55
|
+
return;
|
|
56
|
+
const piece = board.pieces[square];
|
|
57
|
+
// Click on own piece: select it
|
|
58
|
+
if (piece && piece.color === board.toMove) {
|
|
59
|
+
const moves = legalMoves
|
|
60
|
+
.filter((m) => m.from === square)
|
|
61
|
+
.map((m) => m.to);
|
|
62
|
+
setSelection({
|
|
63
|
+
...selection,
|
|
64
|
+
selectedSquare: square,
|
|
65
|
+
legalMoves: moves,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
// Click on destination: try move
|
|
69
|
+
else if (selection.selectedSquare !== null && selection.legalMoves.includes(square)) {
|
|
70
|
+
makeMove({ from: selection.selectedSquare, to: square });
|
|
71
|
+
}
|
|
72
|
+
// Click elsewhere: deselect
|
|
73
|
+
else {
|
|
74
|
+
setSelection({
|
|
75
|
+
...selection,
|
|
76
|
+
selectedSquare: null,
|
|
77
|
+
legalMoves: [],
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}, [board, selection, legalMoves]);
|
|
81
|
+
/**
|
|
82
|
+
* Validate a move against the generated legal moves and apply it.
|
|
83
|
+
*
|
|
84
|
+
* Rejection is reported by return value rather than an exception, so a UI can
|
|
85
|
+
* treat an illegal drop as a no-op. `applyMove` produces a new board rather
|
|
86
|
+
* than mutating, which is what makes the position safe to hold in state.
|
|
87
|
+
*
|
|
88
|
+
* @param move - Move to attempt; only `from` and `to` are matched against the
|
|
89
|
+
* legal move list.
|
|
90
|
+
* @returns `true` if the move was applied, `false` if it was illegal or no
|
|
91
|
+
* board is loaded.
|
|
92
|
+
*/
|
|
93
|
+
const makeMove = useCallback((move) => {
|
|
94
|
+
if (!board)
|
|
95
|
+
return false;
|
|
96
|
+
const isLegal = legalMoves.some((m) => m.from === move.from && m.to === move.to);
|
|
97
|
+
if (!isLegal)
|
|
98
|
+
return false;
|
|
99
|
+
const newBoard = applyMove(board, move);
|
|
100
|
+
setBoard(newBoard);
|
|
101
|
+
setSelection({
|
|
102
|
+
selectedSquare: null,
|
|
103
|
+
legalMoves: [],
|
|
104
|
+
lastMove: { from: move.from, to: move.to },
|
|
105
|
+
});
|
|
106
|
+
return true;
|
|
107
|
+
}, [board, legalMoves]);
|
|
108
|
+
/**
|
|
109
|
+
* Return to the standard starting position and clear all selection state,
|
|
110
|
+
* including `lastMove`. Does not restore the hook's `initialHfen`.
|
|
111
|
+
*/
|
|
112
|
+
const reset = useCallback(() => {
|
|
113
|
+
setBoard(createBoard());
|
|
114
|
+
setSelection({
|
|
115
|
+
selectedSquare: null,
|
|
116
|
+
legalMoves: [],
|
|
117
|
+
lastMove: null,
|
|
118
|
+
});
|
|
119
|
+
}, []);
|
|
120
|
+
return {
|
|
121
|
+
board,
|
|
122
|
+
selection,
|
|
123
|
+
selectSquare,
|
|
124
|
+
makeMove,
|
|
125
|
+
reset,
|
|
126
|
+
legalMoves,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=useBoardState.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useBoardState.js","sourceRoot":"","sources":["../../src/React/useBoardState.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { Board as BoardType, Move, HfenString } from 'hyperchess-core';
|
|
2
|
+
import type { SelectionState } from '../types/props';
|
|
3
|
+
/**
|
|
4
|
+
* Vue 3 composable owning the board position and click-to-move selection.
|
|
5
|
+
*
|
|
6
|
+
* Behaviourally identical to the React hook of the same name — the split exists
|
|
7
|
+
* only because the two frameworks' reactivity primitives differ. `initialHfen`
|
|
8
|
+
* seeds the composable once; later changes are ignored, and `reset()` returns to
|
|
9
|
+
* the standard starting position rather than to `initialHfen`.
|
|
10
|
+
*
|
|
11
|
+
* @param initialHfen - Starting position as an HFEN string or a prebuilt
|
|
12
|
+
* `Board`. A `Board` is adopted by reference, not copied. Omitted means the
|
|
13
|
+
* standard opening position.
|
|
14
|
+
* @returns Reactive `board` and `selection` refs, a computed `legalMoves` for
|
|
15
|
+
* the side to move, and the `selectSquare` / `makeMove` / `reset` actions.
|
|
16
|
+
*/
|
|
17
|
+
export declare function useBoardState(initialHfen?: HfenString | BoardType): {
|
|
18
|
+
board: import("vue").Ref<{
|
|
19
|
+
pieces: ({
|
|
20
|
+
type: import("hyperchess-core").PieceType;
|
|
21
|
+
color: import("hyperchess-core").Color;
|
|
22
|
+
identity?: string | undefined;
|
|
23
|
+
} | undefined)[];
|
|
24
|
+
toMove: import("hyperchess-core").Color;
|
|
25
|
+
enPassantSquare: number;
|
|
26
|
+
castlingRights: {
|
|
27
|
+
whiteKingSide: boolean;
|
|
28
|
+
whiteQueenSide: boolean;
|
|
29
|
+
blackKingSide: boolean;
|
|
30
|
+
blackQueenSide: boolean;
|
|
31
|
+
};
|
|
32
|
+
halfmoveClock: number;
|
|
33
|
+
fullmoveNumber: number;
|
|
34
|
+
history: {
|
|
35
|
+
pieces: ({
|
|
36
|
+
type: import("hyperchess-core").PieceType;
|
|
37
|
+
color: import("hyperchess-core").Color;
|
|
38
|
+
identity?: string | undefined;
|
|
39
|
+
} | undefined)[];
|
|
40
|
+
toMove: import("hyperchess-core").Color;
|
|
41
|
+
enPassantSquare: number;
|
|
42
|
+
castlingRights: {
|
|
43
|
+
whiteKingSide: boolean;
|
|
44
|
+
whiteQueenSide: boolean;
|
|
45
|
+
blackKingSide: boolean;
|
|
46
|
+
blackQueenSide: boolean;
|
|
47
|
+
};
|
|
48
|
+
halfmoveClock: number;
|
|
49
|
+
fullmoveNumber: number;
|
|
50
|
+
}[];
|
|
51
|
+
} | null, BoardType | {
|
|
52
|
+
pieces: ({
|
|
53
|
+
type: import("hyperchess-core").PieceType;
|
|
54
|
+
color: import("hyperchess-core").Color;
|
|
55
|
+
identity?: string | undefined;
|
|
56
|
+
} | undefined)[];
|
|
57
|
+
toMove: import("hyperchess-core").Color;
|
|
58
|
+
enPassantSquare: number;
|
|
59
|
+
castlingRights: {
|
|
60
|
+
whiteKingSide: boolean;
|
|
61
|
+
whiteQueenSide: boolean;
|
|
62
|
+
blackKingSide: boolean;
|
|
63
|
+
blackQueenSide: boolean;
|
|
64
|
+
};
|
|
65
|
+
halfmoveClock: number;
|
|
66
|
+
fullmoveNumber: number;
|
|
67
|
+
history: {
|
|
68
|
+
pieces: ({
|
|
69
|
+
type: import("hyperchess-core").PieceType;
|
|
70
|
+
color: import("hyperchess-core").Color;
|
|
71
|
+
identity?: string | undefined;
|
|
72
|
+
} | undefined)[];
|
|
73
|
+
toMove: import("hyperchess-core").Color;
|
|
74
|
+
enPassantSquare: number;
|
|
75
|
+
castlingRights: {
|
|
76
|
+
whiteKingSide: boolean;
|
|
77
|
+
whiteQueenSide: boolean;
|
|
78
|
+
blackKingSide: boolean;
|
|
79
|
+
blackQueenSide: boolean;
|
|
80
|
+
};
|
|
81
|
+
halfmoveClock: number;
|
|
82
|
+
fullmoveNumber: number;
|
|
83
|
+
}[];
|
|
84
|
+
} | null>;
|
|
85
|
+
selection: import("vue").Ref<{
|
|
86
|
+
selectedSquare: number | null;
|
|
87
|
+
legalMoves: number[];
|
|
88
|
+
lastMove: {
|
|
89
|
+
from: number;
|
|
90
|
+
to: number;
|
|
91
|
+
} | null;
|
|
92
|
+
}, SelectionState | {
|
|
93
|
+
selectedSquare: number | null;
|
|
94
|
+
legalMoves: number[];
|
|
95
|
+
lastMove: {
|
|
96
|
+
from: number;
|
|
97
|
+
to: number;
|
|
98
|
+
} | null;
|
|
99
|
+
}>;
|
|
100
|
+
selectSquare: (square: number) => void;
|
|
101
|
+
makeMove: (move: Move) => boolean;
|
|
102
|
+
reset: () => void;
|
|
103
|
+
legalMoves: import("vue").ComputedRef<Move[]>;
|
|
104
|
+
};
|
|
105
|
+
//# sourceMappingURL=useBoardState.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useBoardState.d.ts","sourceRoot":"","sources":["../../src/Vue/useBoardState.ts"],"names":[],"mappings":"AAOA,OAAO,EACL,KAAK,IAAI,SAAS,EAClB,IAAI,EACJ,UAAU,EAIX,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAErD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,aAAa,CAAC,WAAW,CAAC,EAAE,UAAU,GAAG,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2BA2BlC,MAAM;qBAsCZ,IAAI;;;EAsC7B"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
2
|
+
// HyperChess Core — hyperchess-board-ui
|
|
3
|
+
// File: packages/board/src/Vue/useBoardState.ts
|
|
4
|
+
// Version: 1.0.0
|
|
5
|
+
// Copyright (c) 2026 HyperChess Developer Team
|
|
6
|
+
import { ref, computed } from 'vue';
|
|
7
|
+
import { createBoard, applyMove, generateLegalMoves, } from 'hyperchess-core';
|
|
8
|
+
/**
|
|
9
|
+
* Vue 3 composable owning the board position and click-to-move selection.
|
|
10
|
+
*
|
|
11
|
+
* Behaviourally identical to the React hook of the same name — the split exists
|
|
12
|
+
* only because the two frameworks' reactivity primitives differ. `initialHfen`
|
|
13
|
+
* seeds the composable once; later changes are ignored, and `reset()` returns to
|
|
14
|
+
* the standard starting position rather than to `initialHfen`.
|
|
15
|
+
*
|
|
16
|
+
* @param initialHfen - Starting position as an HFEN string or a prebuilt
|
|
17
|
+
* `Board`. A `Board` is adopted by reference, not copied. Omitted means the
|
|
18
|
+
* standard opening position.
|
|
19
|
+
* @returns Reactive `board` and `selection` refs, a computed `legalMoves` for
|
|
20
|
+
* the side to move, and the `selectSquare` / `makeMove` / `reset` actions.
|
|
21
|
+
*/
|
|
22
|
+
export function useBoardState(initialHfen) {
|
|
23
|
+
// `ref()` takes a value, not a lazy-initializer function like React's
|
|
24
|
+
// `useState` — compute the initial board up front instead.
|
|
25
|
+
const initialBoard = !initialHfen ? createBoard() : typeof initialHfen === 'string' ? createBoard(initialHfen) : initialHfen;
|
|
26
|
+
const board = ref(initialBoard);
|
|
27
|
+
const selection = ref({
|
|
28
|
+
selectedSquare: null,
|
|
29
|
+
legalMoves: [],
|
|
30
|
+
lastMove: null,
|
|
31
|
+
});
|
|
32
|
+
const legalMoves = computed(() => {
|
|
33
|
+
if (!board.value)
|
|
34
|
+
return [];
|
|
35
|
+
return generateLegalMoves(board.value);
|
|
36
|
+
});
|
|
37
|
+
/**
|
|
38
|
+
* Handle a click on a square, driving the three-state selection cycle.
|
|
39
|
+
*
|
|
40
|
+
* Clicking one's own piece selects it, clicking a highlighted destination
|
|
41
|
+
* plays the move, and any other click clears the selection while preserving
|
|
42
|
+
* `lastMove` so the last-move highlight does not flicker.
|
|
43
|
+
*
|
|
44
|
+
* @param square - Flat board index that was clicked.
|
|
45
|
+
*/
|
|
46
|
+
const selectSquare = (square) => {
|
|
47
|
+
if (!board.value)
|
|
48
|
+
return;
|
|
49
|
+
const piece = board.value.pieces[square];
|
|
50
|
+
if (piece && piece.color === board.value.toMove) {
|
|
51
|
+
const moves = legalMoves.value.filter((m) => m.from === square).map((m) => m.to);
|
|
52
|
+
selection.value = {
|
|
53
|
+
...selection.value,
|
|
54
|
+
selectedSquare: square,
|
|
55
|
+
legalMoves: moves,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
else if (selection.value.selectedSquare !== null &&
|
|
59
|
+
selection.value.legalMoves.includes(square)) {
|
|
60
|
+
makeMove({ from: selection.value.selectedSquare, to: square });
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
selection.value = {
|
|
64
|
+
...selection.value,
|
|
65
|
+
selectedSquare: null,
|
|
66
|
+
legalMoves: [],
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* Validate a move against the computed legal moves and apply it.
|
|
72
|
+
*
|
|
73
|
+
* Assigning the new board to `board.value` rather than mutating in place is
|
|
74
|
+
* what lets `legalMoves` recompute.
|
|
75
|
+
*
|
|
76
|
+
* @param move - Move to attempt; only `from` and `to` are matched against the
|
|
77
|
+
* legal move list.
|
|
78
|
+
* @returns `true` if the move was applied, `false` if it was illegal or no
|
|
79
|
+
* board is loaded.
|
|
80
|
+
*/
|
|
81
|
+
const makeMove = (move) => {
|
|
82
|
+
if (!board.value)
|
|
83
|
+
return false;
|
|
84
|
+
const isLegal = legalMoves.value.some((m) => m.from === move.from && m.to === move.to);
|
|
85
|
+
if (!isLegal)
|
|
86
|
+
return false;
|
|
87
|
+
board.value = applyMove(board.value, move);
|
|
88
|
+
selection.value = {
|
|
89
|
+
selectedSquare: null,
|
|
90
|
+
legalMoves: [],
|
|
91
|
+
lastMove: { from: move.from, to: move.to },
|
|
92
|
+
};
|
|
93
|
+
return true;
|
|
94
|
+
};
|
|
95
|
+
/**
|
|
96
|
+
* Return to the standard starting position and clear all selection state,
|
|
97
|
+
* including `lastMove`. Does not restore the composable's `initialHfen`.
|
|
98
|
+
*/
|
|
99
|
+
const reset = () => {
|
|
100
|
+
board.value = createBoard();
|
|
101
|
+
selection.value = {
|
|
102
|
+
selectedSquare: null,
|
|
103
|
+
legalMoves: [],
|
|
104
|
+
lastMove: null,
|
|
105
|
+
};
|
|
106
|
+
};
|
|
107
|
+
return {
|
|
108
|
+
board,
|
|
109
|
+
selection,
|
|
110
|
+
selectSquare,
|
|
111
|
+
makeMove,
|
|
112
|
+
reset,
|
|
113
|
+
legalMoves,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=useBoardState.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useBoardState.js","sourceRoot":"","sources":["../../src/Vue/useBoardState.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { Board, HfenString } from 'hyperchess-core';
|
|
2
|
+
import { Move } from 'hyperchess-core';
|
|
3
|
+
/**
|
|
4
|
+
* Name of a theme to resolve from `hyperchess-theme`.
|
|
5
|
+
*
|
|
6
|
+
* The known names are listed for editor autocompletion only — the trailing
|
|
7
|
+
* `string` widens the union, so any registered custom theme name is accepted and
|
|
8
|
+
* an unknown name is a runtime rather than a compile-time error.
|
|
9
|
+
*/
|
|
10
|
+
export type Theme = 'classic' | 'modern' | 'dark' | 'highcontrast' | string;
|
|
11
|
+
/**
|
|
12
|
+
* What the user is allowed to do with the board: `view` is read-only, `play`
|
|
13
|
+
* accepts only legal moves for the side to move, and `analyze` allows moving
|
|
14
|
+
* either side freely for exploring variations.
|
|
15
|
+
*/
|
|
16
|
+
export type InteractionMode = 'view' | 'play' | 'analyze';
|
|
17
|
+
/**
|
|
18
|
+
* Props accepted by the board component across all framework bindings.
|
|
19
|
+
*
|
|
20
|
+
* Every field is optional; the component is fully usable with no props and falls
|
|
21
|
+
* back to the standard 12x12 HyperChess starting position. Square indices used
|
|
22
|
+
* by the callbacks are flat 0-based offsets into the board, not file/rank pairs.
|
|
23
|
+
*/
|
|
24
|
+
export interface BoardProps {
|
|
25
|
+
/** Initial board state (HFEN or Board object) */
|
|
26
|
+
hfen?: HfenString | Board;
|
|
27
|
+
/** Theme name or custom theme */
|
|
28
|
+
theme?: Theme;
|
|
29
|
+
/** Called after a move has been validated and applied, never for a rejected one. */
|
|
30
|
+
onMove?: (move: Move) => void;
|
|
31
|
+
/** Called for every square click, including clicks that select nothing. */
|
|
32
|
+
onSquareClick?: (square: number) => void;
|
|
33
|
+
/** Enable drag-and-drop moves */
|
|
34
|
+
enableDragDrop?: boolean;
|
|
35
|
+
/** Show rank/file coordinates */
|
|
36
|
+
showCoordinates?: boolean;
|
|
37
|
+
/** Render from black's perspective. Affects display only — square indices
|
|
38
|
+
* passed to callbacks stay in the engine's orientation. */
|
|
39
|
+
flipBoard?: boolean;
|
|
40
|
+
/** Highlight last move */
|
|
41
|
+
highlightLastMove?: boolean;
|
|
42
|
+
/** Highlight legal moves for selected piece */
|
|
43
|
+
highlightLegalMoves?: boolean;
|
|
44
|
+
/** Interaction mode */
|
|
45
|
+
mode?: InteractionMode;
|
|
46
|
+
/** Disable user interaction */
|
|
47
|
+
disabled?: boolean;
|
|
48
|
+
/** Custom CSS class */
|
|
49
|
+
className?: string;
|
|
50
|
+
/** Piece style (unicode, svg, or font) */
|
|
51
|
+
pieceStyle?: 'unicode' | 'svg' | 'font';
|
|
52
|
+
/** Animation speed (ms for move animation) */
|
|
53
|
+
animationSpeed?: number;
|
|
54
|
+
/** Edge length in pixels, or `'responsive'` to fill the container while
|
|
55
|
+
* holding a square aspect ratio. */
|
|
56
|
+
size?: number | 'responsive';
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Transient UI state tracked while the user interacts with the board.
|
|
60
|
+
*
|
|
61
|
+
* Kept separate from the game state so that selecting and deselecting never
|
|
62
|
+
* touches the position — only a completed move does.
|
|
63
|
+
*/
|
|
64
|
+
export interface SelectionState {
|
|
65
|
+
/** Square the user has picked up, or `null` when nothing is selected. */
|
|
66
|
+
selectedSquare: number | null;
|
|
67
|
+
/** Destination squares reachable from `selectedSquare`, for highlighting.
|
|
68
|
+
* Empty whenever nothing is selected. */
|
|
69
|
+
legalMoves: number[];
|
|
70
|
+
/** Most recent move played on this board, for the last-move highlight. It
|
|
71
|
+
* survives selection changes and is cleared only by a reset. */
|
|
72
|
+
lastMove: {
|
|
73
|
+
from: number;
|
|
74
|
+
to: number;
|
|
75
|
+
} | null;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* The full set of interaction callbacks a board renderer must wire up.
|
|
79
|
+
*
|
|
80
|
+
* Unlike the optional handlers on {@link BoardProps} these are all required —
|
|
81
|
+
* this is the internal contract between a renderer and its state hook, not the
|
|
82
|
+
* public component surface.
|
|
83
|
+
*/
|
|
84
|
+
export interface BoardHandlers {
|
|
85
|
+
onMove: (move: Move) => void;
|
|
86
|
+
onSquareClick: (square: number) => void;
|
|
87
|
+
onDragStart: (square: number) => void;
|
|
88
|
+
onDragEnd: (square: number) => void;
|
|
89
|
+
/** Fired on a completed drag; the move still has to pass legality checks. */
|
|
90
|
+
onDrop: (from: number, to: number) => void;
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=props.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"props.d.ts","sourceRoot":"","sources":["../../src/types/props.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAEvC;;;;;;GAMG;AACH,MAAM,MAAM,KAAK,GAAG,SAAS,GAAG,QAAQ,GAAG,MAAM,GAAG,cAAc,GAAG,MAAM,CAAC;AAE5E;;;;GAIG;AACH,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;AAE1D;;;;;;GAMG;AACH,MAAM,WAAW,UAAU;IACzB,iDAAiD;IACjD,IAAI,CAAC,EAAE,UAAU,GAAG,KAAK,CAAC;IAE1B,iCAAiC;IACjC,KAAK,CAAC,EAAE,KAAK,CAAC;IAEd,oFAAoF;IACpF,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IAE9B,2EAA2E;IAC3E,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAEzC,iCAAiC;IACjC,cAAc,CAAC,EAAE,OAAO,CAAC;IAEzB,iCAAiC;IACjC,eAAe,CAAC,EAAE,OAAO,CAAC;IAE1B;+DAC2D;IAC3D,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB,0BAA0B;IAC1B,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAE5B,+CAA+C;IAC/C,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAE9B,uBAAuB;IACvB,IAAI,CAAC,EAAE,eAAe,CAAC;IAEvB,+BAA+B;IAC/B,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,uBAAuB;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,0CAA0C;IAC1C,UAAU,CAAC,EAAE,SAAS,GAAG,KAAK,GAAG,MAAM,CAAC;IAExC,8CAA8C;IAC9C,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB;wCACoC;IACpC,IAAI,CAAC,EAAE,MAAM,GAAG,YAAY,CAAC;CAC9B;AAED;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC7B,yEAAyE;IACzE,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAE9B;6CACyC;IACzC,UAAU,EAAE,MAAM,EAAE,CAAC;IAErB;oEACgE;IAChE,QAAQ,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CAC/C;AAED;;;;;;GAMG;AACH,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IAC7B,aAAa,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,WAAW,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,6EAA6E;IAC7E,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;CAC5C"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"props.js","sourceRoot":"","sources":["../../src/types/props.ts"],"names":[],"mappings":"AAAA,4CAA4C;AAC5C,wCAAwC;AACxC,0CAA0C;AAC1C,iBAAiB;AACjB,+CAA+C"}
|