@dxos/react-ui-gameboard 0.8.4-main.84f28bd → 0.8.4-main.b97322e
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/lib/browser/index.mjs +147 -156
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +147 -156
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/types/src/Chessboard/Chessboard.d.ts +5 -4
- package/dist/types/src/Chessboard/Chessboard.d.ts.map +1 -1
- package/dist/types/src/Chessboard/Chessboard.stories.d.ts.map +1 -1
- package/dist/types/src/Chessboard/chess.d.ts +2 -2
- package/dist/types/src/Chessboard/chess.d.ts.map +1 -1
- package/dist/types/src/Gameboard/Gameboard.d.ts +23 -0
- package/dist/types/src/Gameboard/Gameboard.d.ts.map +1 -0
- package/dist/types/src/Gameboard/Piece.d.ts.map +1 -0
- package/dist/types/src/Gameboard/Square.d.ts.map +1 -0
- package/dist/types/src/Gameboard/context.d.ts +10 -0
- package/dist/types/src/Gameboard/context.d.ts.map +1 -0
- package/dist/types/src/{Board → Gameboard}/index.d.ts +1 -2
- package/dist/types/src/Gameboard/index.d.ts.map +1 -0
- package/dist/types/src/{Board → Gameboard}/types.d.ts +1 -1
- package/dist/types/src/Gameboard/types.d.ts.map +1 -0
- package/dist/types/src/Gameboard/util.d.ts.map +1 -0
- package/dist/types/src/index.d.ts +1 -1
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +13 -13
- package/src/Chessboard/Chessboard.stories.tsx +9 -7
- package/src/Chessboard/Chessboard.tsx +115 -111
- package/src/Chessboard/chess.ts +3 -3
- package/src/{Board/Board.tsx → Gameboard/Gameboard.tsx} +36 -19
- package/src/Gameboard/context.ts +22 -0
- package/src/{Board → Gameboard}/index.ts +1 -2
- package/src/{Board → Gameboard}/types.ts +1 -1
- package/src/index.ts +1 -1
- package/dist/types/src/Board/Board.d.ts +0 -15
- package/dist/types/src/Board/Board.d.ts.map +0 -1
- package/dist/types/src/Board/Container.d.ts +0 -14
- package/dist/types/src/Board/Container.d.ts.map +0 -1
- package/dist/types/src/Board/Piece.d.ts.map +0 -1
- package/dist/types/src/Board/Square.d.ts.map +0 -1
- package/dist/types/src/Board/context.d.ts +0 -10
- package/dist/types/src/Board/context.d.ts.map +0 -1
- package/dist/types/src/Board/index.d.ts.map +0 -1
- package/dist/types/src/Board/types.d.ts.map +0 -1
- package/dist/types/src/Board/util.d.ts.map +0 -1
- package/src/Board/Container.tsx +0 -25
- package/src/Board/context.ts +0 -22
- /package/dist/types/src/{Board → Gameboard}/Piece.d.ts +0 -0
- /package/dist/types/src/{Board → Gameboard}/Square.d.ts +0 -0
- /package/dist/types/src/{Board → Gameboard}/util.d.ts +0 -0
- /package/src/{Board → Gameboard}/Piece.tsx +0 -0
- /package/src/{Board → Gameboard}/Square.tsx +0 -0
- /package/src/{Board → Gameboard}/util.ts +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/react-ui-gameboard",
|
|
3
|
-
"version": "0.8.4-main.
|
|
3
|
+
"version": "0.8.4-main.b97322e",
|
|
4
4
|
"description": "Game board.",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -29,11 +29,11 @@
|
|
|
29
29
|
"@preact/signals-core": "^1.9.0",
|
|
30
30
|
"chess.js": "^1.0.0",
|
|
31
31
|
"react-resize-detector": "^11.0.1",
|
|
32
|
-
"@dxos/debug": "0.8.4-main.
|
|
33
|
-
"@dxos/
|
|
34
|
-
"@dxos/
|
|
35
|
-
"@dxos/
|
|
36
|
-
"@dxos/util": "0.8.4-main.
|
|
32
|
+
"@dxos/debug": "0.8.4-main.b97322e",
|
|
33
|
+
"@dxos/invariant": "0.8.4-main.b97322e",
|
|
34
|
+
"@dxos/node-std": "0.8.4-main.b97322e",
|
|
35
|
+
"@dxos/log": "0.8.4-main.b97322e",
|
|
36
|
+
"@dxos/util": "0.8.4-main.b97322e"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"@svgr/cli": "^8.1.0",
|
|
@@ -44,15 +44,15 @@
|
|
|
44
44
|
"react": "~18.2.0",
|
|
45
45
|
"react-dom": "~18.2.0",
|
|
46
46
|
"vite": "5.4.7",
|
|
47
|
-
"@dxos/react-ui": "0.8.4-main.
|
|
48
|
-
"@dxos/react-ui
|
|
49
|
-
"@dxos/storybook-utils": "0.8.4-main.
|
|
47
|
+
"@dxos/react-ui-theme": "0.8.4-main.b97322e",
|
|
48
|
+
"@dxos/react-ui": "0.8.4-main.b97322e",
|
|
49
|
+
"@dxos/storybook-utils": "0.8.4-main.b97322e"
|
|
50
50
|
},
|
|
51
51
|
"peerDependencies": {
|
|
52
52
|
"react": "~18.2.0",
|
|
53
53
|
"react-dom": "~18.2.0",
|
|
54
|
-
"@dxos/react-ui": "0.8.4-main.
|
|
55
|
-
"@dxos/react-ui-theme": "0.8.4-main.
|
|
54
|
+
"@dxos/react-ui": "0.8.4-main.b97322e",
|
|
55
|
+
"@dxos/react-ui-theme": "0.8.4-main.b97322e"
|
|
56
56
|
},
|
|
57
57
|
"publishConfig": {
|
|
58
58
|
"access": "public"
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
"scripts": {
|
|
61
61
|
"gen:pieces": "pnpm gen:pieces:chess",
|
|
62
62
|
"gen:pieces:chess": "pnpm gen:pieces:chess:alpha && pnpm gen:pieces:chess:cburnett",
|
|
63
|
-
"gen:pieces:chess:alpha": "pnpm svgr --typescript --filename-case=camel --out-dir ./src/gen/pieces/chess/alpha ./assets/pieces/chess/alpha",
|
|
64
|
-
"gen:pieces:chess:cburnett": "pnpm svgr --typescript --filename-case=camel --out-dir ./src/gen/pieces/chess/cburnett ./assets/pieces/chess/cburnett"
|
|
63
|
+
"gen:pieces:chess:alpha": "pnpm svgr --typescript --filename-case=camel --out-dir ./src/gen/pieces/chess/alpha ./assets/pieces/chess/alpha > /dev/null",
|
|
64
|
+
"gen:pieces:chess:cburnett": "pnpm svgr --typescript --filename-case=camel --out-dir ./src/gen/pieces/chess/cburnett ./assets/pieces/chess/cburnett > /dev/null"
|
|
65
65
|
}
|
|
66
66
|
}
|
|
@@ -13,7 +13,7 @@ import { withLayout, withTheme } from '@dxos/storybook-utils';
|
|
|
13
13
|
|
|
14
14
|
import { Chessboard, type ChessboardProps } from './Chessboard';
|
|
15
15
|
import { ChessModel } from './chess';
|
|
16
|
-
import {
|
|
16
|
+
import { Gameboard, type GameboardRootProps, type Player, type Move } from '../Gameboard';
|
|
17
17
|
|
|
18
18
|
type RenderProps = Pick<ChessboardProps, 'orientation' | 'showLabels' | 'debug'> & {
|
|
19
19
|
fen: string;
|
|
@@ -23,7 +23,7 @@ const DefaultStory = ({ fen, orientation: _orientation, ...props }: RenderProps)
|
|
|
23
23
|
const model = useMemo(() => new ChessModel(fen), [fen]);
|
|
24
24
|
const [orientation, setOrientation] = useState<Player | undefined>(_orientation);
|
|
25
25
|
|
|
26
|
-
const handleDrop = useCallback<NonNullable<
|
|
26
|
+
const handleDrop = useCallback<NonNullable<GameboardRootProps['onDrop']>>(
|
|
27
27
|
(move: Move) => {
|
|
28
28
|
log.info('handleDrop', { move });
|
|
29
29
|
return model.makeMove(move);
|
|
@@ -43,9 +43,11 @@ const DefaultStory = ({ fen, orientation: _orientation, ...props }: RenderProps)
|
|
|
43
43
|
Toggle
|
|
44
44
|
</Button>
|
|
45
45
|
</Toolbar.Root>
|
|
46
|
-
<
|
|
47
|
-
<
|
|
48
|
-
|
|
46
|
+
<Gameboard.Root model={model} onDrop={handleDrop}>
|
|
47
|
+
<Gameboard.Content>
|
|
48
|
+
<Chessboard orientation={orientation} {...props} />
|
|
49
|
+
</Gameboard.Content>
|
|
50
|
+
</Gameboard.Root>
|
|
49
51
|
</div>
|
|
50
52
|
);
|
|
51
53
|
};
|
|
@@ -65,9 +67,9 @@ const Grid = (props: RenderProps) => {
|
|
|
65
67
|
<div className='grid grid-cols-3 gap-2'>
|
|
66
68
|
{models.map((model, i) => (
|
|
67
69
|
<div key={i} className='aspect-square'>
|
|
68
|
-
<
|
|
70
|
+
<Gameboard.Root model={model}>
|
|
69
71
|
<Chessboard />
|
|
70
|
-
</
|
|
72
|
+
</Gameboard.Root>
|
|
71
73
|
</div>
|
|
72
74
|
))}
|
|
73
75
|
</div>
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import React, { type PropsWithChildren, useRef, useMemo, useEffect, useState, memo } from 'react';
|
|
6
6
|
import { useResizeDetector } from 'react-resize-detector';
|
|
7
7
|
|
|
8
|
-
import { useTrackProps } from '@dxos/react-ui';
|
|
8
|
+
import { type ThemedClassName, useTrackProps } from '@dxos/react-ui';
|
|
9
9
|
import { mx } from '@dxos/react-ui-theme';
|
|
10
10
|
import { isNotFalsy } from '@dxos/util';
|
|
11
11
|
|
|
@@ -19,126 +19,130 @@ import {
|
|
|
19
19
|
Square,
|
|
20
20
|
getRelativeBounds,
|
|
21
21
|
locationToString,
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
export type ChessboardProps =
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
22
|
+
useBoardContext,
|
|
23
|
+
} from '../Gameboard';
|
|
24
|
+
|
|
25
|
+
export type ChessboardProps = ThemedClassName<
|
|
26
|
+
PropsWithChildren<{
|
|
27
|
+
orientation?: Player;
|
|
28
|
+
showLabels?: boolean;
|
|
29
|
+
debug?: boolean;
|
|
30
|
+
rows?: number;
|
|
31
|
+
cols?: number;
|
|
32
|
+
}>
|
|
33
|
+
>;
|
|
32
34
|
|
|
33
35
|
/**
|
|
34
36
|
* Chessboard layout.
|
|
35
37
|
*/
|
|
36
|
-
export const Chessboard = memo(
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
Array.from({ length:
|
|
44
|
-
|
|
45
|
-
}, [orientation, rows, cols]);
|
|
46
|
-
|
|
47
|
-
// Use DOM grid layout to position squares.
|
|
48
|
-
const layout = useMemo(() => {
|
|
49
|
-
return locations.map((location) => {
|
|
50
|
-
return (
|
|
51
|
-
<div
|
|
52
|
-
key={locationToString(location)}
|
|
53
|
-
{...{
|
|
54
|
-
['data-location' as const]: locationToString(location),
|
|
55
|
-
}}
|
|
56
|
-
/>
|
|
38
|
+
export const Chessboard = memo(
|
|
39
|
+
({ orientation, showLabels, debug, rows = 8, cols = 8, classNames }: ChessboardProps) => {
|
|
40
|
+
useTrackProps({ orientation, showLabels, debug }, Chessboard.displayName, false);
|
|
41
|
+
const { ref: containerRef, width, height } = useResizeDetector({ refreshRate: 200 });
|
|
42
|
+
const { model, promoting, onPromotion } = useBoardContext();
|
|
43
|
+
|
|
44
|
+
const locations = useMemo<Location[]>(() => {
|
|
45
|
+
return Array.from({ length: rows }, (_, i) => (orientation === 'black' ? i : rows - 1 - i)).flatMap((row) =>
|
|
46
|
+
Array.from({ length: cols }).map((_, col) => [row, col] as Location),
|
|
57
47
|
);
|
|
58
|
-
});
|
|
59
|
-
}, [locations]);
|
|
60
|
-
|
|
61
|
-
// Build map of square locations to bounds.
|
|
62
|
-
const [grid, setGrid] = useState<Record<string, DOMRectBounds>>({});
|
|
63
|
-
const gridRef = useRef<HTMLDivElement>(null);
|
|
64
|
-
useEffect(() => {
|
|
65
|
-
setGrid(
|
|
66
|
-
locations.reduce(
|
|
67
|
-
(acc, location) => {
|
|
68
|
-
const square = getSquareLocation(gridRef.current!, location)!;
|
|
69
|
-
const bounds = getRelativeBounds(gridRef.current!, square);
|
|
70
|
-
return { ...acc, [locationToString(location)]: bounds };
|
|
71
|
-
},
|
|
72
|
-
{} as Record<string, DOMRectBounds>,
|
|
73
|
-
),
|
|
74
|
-
);
|
|
75
|
-
}, [locations, width, height]);
|
|
76
|
-
|
|
77
|
-
// Get the bounds of each square and piece.
|
|
78
|
-
const positions = useMemo<{ piece: PieceRecord; bounds: DOMRectBounds }[]>(() => {
|
|
79
|
-
if (!gridRef.current) {
|
|
80
|
-
return [];
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
return Object.values(model?.pieces.value ?? {})
|
|
84
|
-
.map((piece) => {
|
|
85
|
-
if (piece.id === promoting?.id) {
|
|
86
|
-
return null;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
const bounds = grid[locationToString(piece.location)];
|
|
90
|
-
return { piece, bounds };
|
|
91
|
-
})
|
|
92
|
-
.filter(isNotFalsy);
|
|
93
|
-
}, [grid, model?.pieces.value, promoting]);
|
|
48
|
+
}, [orientation, rows, cols]);
|
|
94
49
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
<div>
|
|
101
|
-
{locations.map((location) => (
|
|
102
|
-
<Square
|
|
50
|
+
// Use DOM grid layout to position squares.
|
|
51
|
+
const layout = useMemo(() => {
|
|
52
|
+
return locations.map((location) => {
|
|
53
|
+
return (
|
|
54
|
+
<div
|
|
103
55
|
key={locationToString(location)}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
bounds={grid[locationToString(location)]}
|
|
107
|
-
classNames={getSquareColor(location)}
|
|
108
|
-
/>
|
|
109
|
-
))}
|
|
110
|
-
</div>
|
|
111
|
-
<div className={mx(promoting && 'opacity-50')}>
|
|
112
|
-
{positions.map(({ bounds, piece }) => (
|
|
113
|
-
<Piece
|
|
114
|
-
key={piece.id}
|
|
115
|
-
piece={piece}
|
|
116
|
-
bounds={bounds}
|
|
117
|
-
label={debug ? piece.id : undefined}
|
|
118
|
-
orientation={orientation}
|
|
119
|
-
Component={ChessPieces[piece.type as ChessPiece]}
|
|
120
|
-
/>
|
|
121
|
-
))}
|
|
122
|
-
</div>
|
|
123
|
-
<div>
|
|
124
|
-
{promoting && (
|
|
125
|
-
<PromotionSelector
|
|
126
|
-
grid={grid}
|
|
127
|
-
piece={promoting}
|
|
128
|
-
onSelect={(piece) => {
|
|
129
|
-
onPromotion({
|
|
130
|
-
from: Object.values(model!.pieces.value).find((p) => p.id === promoting.id)!.location,
|
|
131
|
-
to: piece.location,
|
|
132
|
-
piece: promoting.type,
|
|
133
|
-
promotion: piece.type,
|
|
134
|
-
});
|
|
56
|
+
{...{
|
|
57
|
+
['data-location' as const]: locationToString(location),
|
|
135
58
|
}}
|
|
136
59
|
/>
|
|
137
|
-
)
|
|
60
|
+
);
|
|
61
|
+
});
|
|
62
|
+
}, [locations]);
|
|
63
|
+
|
|
64
|
+
// Build map of square locations to bounds.
|
|
65
|
+
const [grid, setGrid] = useState<Record<string, DOMRectBounds>>({});
|
|
66
|
+
const gridRef = useRef<HTMLDivElement>(null);
|
|
67
|
+
useEffect(() => {
|
|
68
|
+
setGrid(
|
|
69
|
+
locations.reduce(
|
|
70
|
+
(acc, location) => {
|
|
71
|
+
const square = getSquareLocation(gridRef.current!, location)!;
|
|
72
|
+
const bounds = getRelativeBounds(gridRef.current!, square);
|
|
73
|
+
return { ...acc, [locationToString(location)]: bounds };
|
|
74
|
+
},
|
|
75
|
+
{} as Record<string, DOMRectBounds>,
|
|
76
|
+
),
|
|
77
|
+
);
|
|
78
|
+
}, [locations, width, height]);
|
|
79
|
+
|
|
80
|
+
// Get the bounds of each square and piece.
|
|
81
|
+
const positions = useMemo<{ piece: PieceRecord; bounds: DOMRectBounds }[]>(() => {
|
|
82
|
+
if (!gridRef.current) {
|
|
83
|
+
return [];
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return Object.values(model?.pieces.value ?? {})
|
|
87
|
+
.map((piece) => {
|
|
88
|
+
if (piece.id === promoting?.id) {
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const bounds = grid[locationToString(piece.location)];
|
|
93
|
+
return { piece, bounds };
|
|
94
|
+
})
|
|
95
|
+
.filter(isNotFalsy);
|
|
96
|
+
}, [grid, model?.pieces.value, promoting]);
|
|
97
|
+
|
|
98
|
+
return (
|
|
99
|
+
<div ref={containerRef} className={mx('relative', classNames)}>
|
|
100
|
+
<div ref={gridRef} className='grid grid-rows-8 grid-cols-8 aspect-square select-none'>
|
|
101
|
+
{layout}
|
|
102
|
+
</div>
|
|
103
|
+
<div>
|
|
104
|
+
{locations.map((location) => (
|
|
105
|
+
<Square
|
|
106
|
+
key={locationToString(location)}
|
|
107
|
+
location={location}
|
|
108
|
+
label={showLabels ? locationToPos(location) : undefined}
|
|
109
|
+
bounds={grid[locationToString(location)]}
|
|
110
|
+
classNames={getSquareColor(location)}
|
|
111
|
+
/>
|
|
112
|
+
))}
|
|
113
|
+
</div>
|
|
114
|
+
<div className={mx(promoting && 'opacity-50')}>
|
|
115
|
+
{positions.map(({ bounds, piece }) => (
|
|
116
|
+
<Piece
|
|
117
|
+
key={piece.id}
|
|
118
|
+
piece={piece}
|
|
119
|
+
bounds={bounds}
|
|
120
|
+
label={debug ? piece.id : undefined}
|
|
121
|
+
orientation={orientation}
|
|
122
|
+
Component={ChessPieces[piece.type as ChessPiece]}
|
|
123
|
+
/>
|
|
124
|
+
))}
|
|
125
|
+
</div>
|
|
126
|
+
<div>
|
|
127
|
+
{promoting && (
|
|
128
|
+
<PromotionSelector
|
|
129
|
+
grid={grid}
|
|
130
|
+
piece={promoting}
|
|
131
|
+
onSelect={(piece) => {
|
|
132
|
+
onPromotion({
|
|
133
|
+
from: Object.values(model!.pieces.value).find((p) => p.id === promoting.id)!.location,
|
|
134
|
+
to: piece.location,
|
|
135
|
+
piece: promoting.type,
|
|
136
|
+
promotion: piece.type,
|
|
137
|
+
});
|
|
138
|
+
}}
|
|
139
|
+
/>
|
|
140
|
+
)}
|
|
141
|
+
</div>
|
|
138
142
|
</div>
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
143
|
+
);
|
|
144
|
+
},
|
|
145
|
+
);
|
|
142
146
|
|
|
143
147
|
Chessboard.displayName = 'Chessboard';
|
|
144
148
|
|
package/src/Chessboard/chess.ts
CHANGED
|
@@ -14,9 +14,9 @@ import {
|
|
|
14
14
|
type PieceMap,
|
|
15
15
|
locationToString,
|
|
16
16
|
type PieceType,
|
|
17
|
-
type
|
|
17
|
+
type GameboardModel,
|
|
18
18
|
type Player,
|
|
19
|
-
} from '../
|
|
19
|
+
} from '../Gameboard';
|
|
20
20
|
import * as Alpha from '../gen/pieces/chess/alpha';
|
|
21
21
|
|
|
22
22
|
export type ChessPiece = 'BK' | 'BQ' | 'BR' | 'BB' | 'BN' | 'BP' | 'WK' | 'WQ' | 'WR' | 'WB' | 'WN' | 'WP';
|
|
@@ -82,7 +82,7 @@ const makeMove = (game: Chess, move: Move): Chess | null => {
|
|
|
82
82
|
/**
|
|
83
83
|
* Chess model.
|
|
84
84
|
*/
|
|
85
|
-
export class ChessModel implements
|
|
85
|
+
export class ChessModel implements GameboardModel<ChessPiece> {
|
|
86
86
|
private _game!: Chess;
|
|
87
87
|
private readonly _pieces = signal<PieceMap<ChessPiece>>({});
|
|
88
88
|
|
|
@@ -3,32 +3,29 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { monitorForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';
|
|
6
|
-
import React, { type PropsWithChildren, useCallback, useEffect, useState } from 'react';
|
|
6
|
+
import React, { type CSSProperties, forwardRef, type PropsWithChildren, useCallback, useEffect, useState } from 'react';
|
|
7
7
|
|
|
8
8
|
import { log } from '@dxos/log';
|
|
9
9
|
import { type ThemedClassName } from '@dxos/react-ui';
|
|
10
10
|
import { mx } from '@dxos/react-ui-theme';
|
|
11
11
|
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import { type BoardModel, isLocation, isPiece, type Move, type PieceRecord } from './types';
|
|
12
|
+
import { GameboardContext, type GameboardContextType } from './context';
|
|
13
|
+
import { type GameboardModel, isLocation, isPiece, type Move, type PieceRecord } from './types';
|
|
15
14
|
|
|
16
|
-
type
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
}>
|
|
21
|
-
>;
|
|
15
|
+
type GameboardRootProps = PropsWithChildren<{
|
|
16
|
+
model?: GameboardModel;
|
|
17
|
+
onDrop?: (move: Move) => boolean;
|
|
18
|
+
}>;
|
|
22
19
|
|
|
23
20
|
/**
|
|
24
21
|
* Generic board container.
|
|
25
22
|
*/
|
|
26
|
-
const
|
|
23
|
+
const GameboardRoot = ({ children, model, onDrop }: GameboardRootProps) => {
|
|
27
24
|
const [dragging, setDragging] = useState(false);
|
|
28
25
|
const [promoting, setPromoting] = useState<PieceRecord | undefined>();
|
|
29
26
|
|
|
30
27
|
// Handle promotion.
|
|
31
|
-
const onPromotion = useCallback<
|
|
28
|
+
const onPromotion = useCallback<GameboardContextType['onPromotion']>((move) => {
|
|
32
29
|
log('onPromotion', { move });
|
|
33
30
|
setPromoting(undefined);
|
|
34
31
|
onDrop?.(move);
|
|
@@ -71,16 +68,36 @@ const Root = ({ children, classNames, model, onDrop }: RootProps) => {
|
|
|
71
68
|
}, [model]);
|
|
72
69
|
|
|
73
70
|
return (
|
|
74
|
-
<
|
|
75
|
-
|
|
76
|
-
</
|
|
71
|
+
<GameboardContext.Provider value={{ model, dragging, promoting, onPromotion }}>
|
|
72
|
+
{children}
|
|
73
|
+
</GameboardContext.Provider>
|
|
77
74
|
);
|
|
78
75
|
};
|
|
79
76
|
|
|
80
|
-
|
|
77
|
+
GameboardRoot.displayName = 'Gameboard.Root';
|
|
78
|
+
|
|
79
|
+
type GameboardContentsProps = ThemedClassName<
|
|
80
|
+
PropsWithChildren<{
|
|
81
|
+
style?: CSSProperties;
|
|
82
|
+
}>
|
|
83
|
+
>;
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Container centers the board.
|
|
87
|
+
*/
|
|
88
|
+
const GameboardContent = forwardRef<HTMLDivElement, GameboardContentsProps>(
|
|
89
|
+
({ children, classNames, style }, forwardedRef) => {
|
|
90
|
+
return (
|
|
91
|
+
<div ref={forwardedRef} style={style} className='flex w-full h-full justify-center overflow-hidden'>
|
|
92
|
+
<div className={mx('max-w-full max-h-full content-center aspect-square', classNames)}>{children}</div>
|
|
93
|
+
</div>
|
|
94
|
+
);
|
|
95
|
+
},
|
|
96
|
+
);
|
|
81
97
|
|
|
82
|
-
export const
|
|
83
|
-
Root,
|
|
98
|
+
export const Gameboard = {
|
|
99
|
+
Root: GameboardRoot,
|
|
100
|
+
Content: GameboardContent,
|
|
84
101
|
};
|
|
85
102
|
|
|
86
|
-
export type {
|
|
103
|
+
export type { GameboardRootProps, GameboardContentsProps };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { createContext, useContext } from 'react';
|
|
6
|
+
|
|
7
|
+
import { raise } from '@dxos/debug';
|
|
8
|
+
|
|
9
|
+
import { type PieceRecord, type GameboardModel, type Move } from './types';
|
|
10
|
+
|
|
11
|
+
export type GameboardContextType = {
|
|
12
|
+
model?: GameboardModel;
|
|
13
|
+
dragging?: boolean; // TODO(burdon): Change to PieceRecord.
|
|
14
|
+
promoting?: PieceRecord;
|
|
15
|
+
onPromotion: (move: Move) => void;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export const GameboardContext = createContext<GameboardContextType | undefined>(undefined);
|
|
19
|
+
|
|
20
|
+
export const useBoardContext = () => {
|
|
21
|
+
return useContext(GameboardContext) ?? raise(new Error('Missing BoardContext'));
|
|
22
|
+
};
|
|
@@ -50,7 +50,7 @@ export const isEqualLocation = (l1: Location, l2: Location): boolean => l1[0] ==
|
|
|
50
50
|
/**
|
|
51
51
|
* Generic board model.
|
|
52
52
|
*/
|
|
53
|
-
export interface
|
|
53
|
+
export interface GameboardModel<T extends PieceType = PieceType> {
|
|
54
54
|
turn: Player;
|
|
55
55
|
pieces: ReadonlySignal<PieceMap<T>>;
|
|
56
56
|
isValidMove: (move: Move) => boolean;
|
package/src/index.ts
CHANGED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import React, { type PropsWithChildren } from 'react';
|
|
2
|
-
import { type ThemedClassName } from '@dxos/react-ui';
|
|
3
|
-
import { type BoardModel, type Move } from './types';
|
|
4
|
-
type RootProps = ThemedClassName<PropsWithChildren<{
|
|
5
|
-
model?: BoardModel;
|
|
6
|
-
onDrop?: (move: Move) => boolean;
|
|
7
|
-
}>>;
|
|
8
|
-
export declare const Board: {
|
|
9
|
-
Root: {
|
|
10
|
-
({ children, classNames, model, onDrop }: RootProps): React.JSX.Element;
|
|
11
|
-
displayName: string;
|
|
12
|
-
};
|
|
13
|
-
};
|
|
14
|
-
export type { RootProps as BoardRootProps };
|
|
15
|
-
//# sourceMappingURL=Board.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Board.d.ts","sourceRoot":"","sources":["../../../../src/Board/Board.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,EAAE,KAAK,iBAAiB,EAAoC,MAAM,OAAO,CAAC;AAGxF,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAKtD,OAAO,EAAE,KAAK,UAAU,EAAuB,KAAK,IAAI,EAAoB,MAAM,SAAS,CAAC;AAE5F,KAAK,SAAS,GAAG,eAAe,CAC9B,iBAAiB,CAAC;IAChB,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC;CAClC,CAAC,CACH,CAAC;AA6DF,eAAO,MAAM,KAAK;;kDAxDqC,SAAS;;;CA0D/D,CAAC;AAEF,YAAY,EAAE,SAAS,IAAI,cAAc,EAAE,CAAC"}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import React, { type CSSProperties, type PropsWithChildren } from 'react';
|
|
2
|
-
import { type ThemedClassName } from '@dxos/react-ui';
|
|
3
|
-
export type ContainerProps = ThemedClassName<PropsWithChildren<{
|
|
4
|
-
style?: CSSProperties;
|
|
5
|
-
}>>;
|
|
6
|
-
/**
|
|
7
|
-
* Container centers the board.
|
|
8
|
-
*/
|
|
9
|
-
export declare const Container: React.ForwardRefExoticComponent<Omit<React.PropsWithChildren<{
|
|
10
|
-
style?: CSSProperties;
|
|
11
|
-
}>, "className"> & {
|
|
12
|
-
classNames?: import("@dxos/react-ui-types").ClassNameValue;
|
|
13
|
-
} & React.RefAttributes<HTMLDivElement>>;
|
|
14
|
-
//# sourceMappingURL=Container.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Container.d.ts","sourceRoot":"","sources":["../../../../src/Board/Container.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,EAAE,KAAK,aAAa,EAAc,KAAK,iBAAiB,EAAE,MAAM,OAAO,CAAC;AAEtF,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAGtD,MAAM,MAAM,cAAc,GAAG,eAAe,CAC1C,iBAAiB,CAAC;IAChB,KAAK,CAAC,EAAE,aAAa,CAAC;CACvB,CAAC,CACH,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,SAAS;YAPV,aAAa;;;wCAavB,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Piece.d.ts","sourceRoot":"","sources":["../../../../src/Board/Piece.tsx"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,EAA+B,KAAK,EAAE,EAAE,KAAK,QAAQ,EAAQ,MAAM,OAAO,CAAC;AAKzF,OAAO,EAAgC,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAIpF,OAAO,EAA8C,KAAK,WAAW,EAAE,KAAK,MAAM,EAAE,MAAM,SAAS,CAAC;AACpG,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,QAAQ,CAAC;AAE5C,MAAM,MAAM,UAAU,GAAG,eAAe,CAAC;IACvC,KAAK,EAAE,WAAW,CAAC;IACnB,MAAM,EAAE,aAAa,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,EAAE,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC;CACxC,CAAC,CAAC;AAEH,eAAO,MAAM,KAAK,2FAAuE,UAAU,uBAwGjG,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Square.d.ts","sourceRoot":"","sources":["../../../../src/Board/Square.tsx"],"names":[],"mappings":"AAKA,OAAO,KAA4C,MAAM,OAAO,CAAC;AAIjE,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAItD,OAAO,EAAW,KAAK,QAAQ,EAAE,MAAM,SAAS,CAAC;AACjD,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,QAAQ,CAAC;AAI5C,MAAM,MAAM,WAAW,GAAG,eAAe,CAAC;IACxC,QAAQ,EAAE,QAAQ,CAAC;IACnB,MAAM,EAAE,aAAa,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC,CAAC;AAEH,eAAO,MAAM,MAAM,sEAAkD,WAAW,uBA+C9E,CAAC"}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { type PieceRecord, type BoardModel, type Move } from './types';
|
|
2
|
-
export type BoardContextType = {
|
|
3
|
-
model?: BoardModel;
|
|
4
|
-
dragging?: boolean;
|
|
5
|
-
promoting?: PieceRecord;
|
|
6
|
-
onPromotion: (move: Move) => void;
|
|
7
|
-
};
|
|
8
|
-
export declare const BoardContext: import("react").Context<BoardContextType | undefined>;
|
|
9
|
-
export declare const useBoardContext: () => BoardContextType;
|
|
10
|
-
//# sourceMappingURL=context.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../../../src/Board/context.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,UAAU,EAAE,KAAK,IAAI,EAAE,MAAM,SAAS,CAAC;AAEvE,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,WAAW,CAAC;IACxB,WAAW,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;CACnC,CAAC;AAEF,eAAO,MAAM,YAAY,uDAAyD,CAAC;AAEnF,eAAO,MAAM,eAAe,wBAE3B,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/Board/index.ts"],"names":[],"mappings":"AAIA,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AACxB,cAAc,QAAQ,CAAC;AAEvB,cAAc,SAAS,CAAC;AACxB,cAAc,aAAa,CAAC;AAC5B,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/Board/types.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D,MAAM,MAAM,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC;AAEvC,MAAM,MAAM,QAAQ,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAExC,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC;AAE/B,MAAM,MAAM,WAAW,CAAC,CAAC,SAAS,SAAS,GAAG,SAAS,IAAI;IACzD,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,CAAC,CAAC;IACR,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,QAAQ,CAAC;CACpB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,QAAQ,CAAC,CAAC,SAAS,SAAS,GAAG,SAAS,IAAI,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;AAEvF,MAAM,MAAM,IAAI,GAAG;IACjB,IAAI,EAAE,QAAQ,CAAC;IACf,EAAE,EAAE,QAAQ,CAAC;IACb,KAAK,EAAE,SAAS,CAAC;IACjB,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAI,UAAU,QAAQ,KAAG,MAA4B,CAAC;AACnF,eAAO,MAAM,gBAAgB,GAAI,KAAK,MAAM,KAAG,QAAkD,CAAC;AAGlG,eAAO,MAAM,OAAO,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,WAMtB,CAAC;AAG7B,eAAO,MAAM,UAAU,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,QACwC,CAAC;AAE9F,eAAO,MAAM,eAAe,GAAI,IAAI,QAAQ,EAAE,IAAI,QAAQ,KAAG,OAA6C,CAAC;AAE3G;;GAEG;AACH,MAAM,WAAW,UAAU,CAAC,CAAC,SAAS,SAAS,GAAG,SAAS;IACzD,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,cAAc,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IACpC,WAAW,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC;IACrC,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC;CACtC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../../../../src/Board/util.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,aAAa,GAAG,IAAI,CAAC,OAAO,EAAE,KAAK,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAC,CAAC;AAE/E,eAAO,MAAM,iBAAiB,GAAI,WAAW,WAAW,EAAE,SAAS,WAAW,KAAG,aAShF,CAAC"}
|
package/src/Board/Container.tsx
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Copyright 2025 DXOS.org
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
import React, { type CSSProperties, forwardRef, type PropsWithChildren } from 'react';
|
|
6
|
-
|
|
7
|
-
import { type ThemedClassName } from '@dxos/react-ui';
|
|
8
|
-
import { mx } from '@dxos/react-ui-theme';
|
|
9
|
-
|
|
10
|
-
export type ContainerProps = ThemedClassName<
|
|
11
|
-
PropsWithChildren<{
|
|
12
|
-
style?: CSSProperties;
|
|
13
|
-
}>
|
|
14
|
-
>;
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Container centers the board.
|
|
18
|
-
*/
|
|
19
|
-
export const Container = forwardRef<HTMLDivElement, ContainerProps>(({ children, classNames, style }, forwardedRef) => {
|
|
20
|
-
return (
|
|
21
|
-
<div ref={forwardedRef} style={style} className='flex w-full h-full justify-center overflow-hidden'>
|
|
22
|
-
<div className={mx('max-w-full max-h-full content-center', classNames)}>{children}</div>
|
|
23
|
-
</div>
|
|
24
|
-
);
|
|
25
|
-
});
|
package/src/Board/context.ts
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Copyright 2025 DXOS.org
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
import { createContext, useContext } from 'react';
|
|
6
|
-
|
|
7
|
-
import { raise } from '@dxos/debug';
|
|
8
|
-
|
|
9
|
-
import { type PieceRecord, type BoardModel, type Move } from './types';
|
|
10
|
-
|
|
11
|
-
export type BoardContextType = {
|
|
12
|
-
model?: BoardModel;
|
|
13
|
-
dragging?: boolean; // TODO(burdon): Change to PieceRecord.
|
|
14
|
-
promoting?: PieceRecord;
|
|
15
|
-
onPromotion: (move: Move) => void;
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
export const BoardContext = createContext<BoardContextType | undefined>(undefined);
|
|
19
|
-
|
|
20
|
-
export const useBoardContext = () => {
|
|
21
|
-
return useContext(BoardContext) ?? raise(new Error('Missing BoardContext'));
|
|
22
|
-
};
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|