@dxos/plugin-chess 0.8.4-main.ae835ea → 0.8.4-main.bc2380dfbc
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 +102 -5
- package/README.md +1 -1
- package/dist/lib/neutral/ChessArticle-QLLKZGPH.mjs +88 -0
- package/dist/lib/neutral/ChessArticle-QLLKZGPH.mjs.map +7 -0
- package/dist/lib/neutral/ChessCard-I5RSZZIP.mjs +19 -0
- package/dist/lib/neutral/ChessCard-I5RSZZIP.mjs.map +7 -0
- package/dist/lib/neutral/ChessPlugin.mjs +10 -0
- package/dist/lib/neutral/ChessPlugin.node.mjs +23 -0
- package/dist/lib/neutral/ChessPlugin.node.mjs.map +7 -0
- package/dist/lib/neutral/ChessPlugin.workerd.mjs +21 -0
- package/dist/lib/neutral/ChessPlugin.workerd.mjs.map +7 -0
- package/dist/lib/neutral/blueprint-definition-PZXHAYLD.mjs +15 -0
- package/dist/lib/neutral/blueprint-definition-PZXHAYLD.mjs.map +7 -0
- package/dist/lib/neutral/blueprints/index.mjs +8 -0
- package/dist/lib/neutral/capabilities/index.mjs +13 -0
- package/dist/lib/neutral/capabilities/index.mjs.map +7 -0
- package/dist/lib/neutral/chunk-5UOTTW6U.mjs +8 -0
- package/dist/lib/neutral/chunk-5UOTTW6U.mjs.map +7 -0
- package/dist/lib/neutral/chunk-E4LZPHAQ.mjs +148 -0
- package/dist/lib/neutral/chunk-E4LZPHAQ.mjs.map +7 -0
- package/dist/lib/neutral/chunk-HVIKFYAW.mjs +29 -0
- package/dist/lib/neutral/chunk-HVIKFYAW.mjs.map +7 -0
- package/dist/lib/neutral/chunk-J5LGTIGS.mjs +10 -0
- package/dist/lib/{browser/chunk-DUO4WTAM.mjs → neutral/chunk-NYIJLMS3.mjs} +6 -9
- package/dist/lib/neutral/chunk-NYIJLMS3.mjs.map +7 -0
- package/dist/lib/neutral/chunk-XWKNXG62.mjs +34 -0
- package/dist/lib/neutral/chunk-XWKNXG62.mjs.map +7 -0
- package/dist/lib/neutral/components/index.mjs +239 -0
- package/dist/lib/neutral/components/index.mjs.map +7 -0
- package/dist/lib/neutral/containers/index.mjs +11 -0
- package/dist/lib/neutral/containers/index.mjs.map +7 -0
- package/dist/lib/neutral/game-variant-24UKIBRM.mjs +40 -0
- package/dist/lib/neutral/game-variant-24UKIBRM.mjs.map +7 -0
- package/dist/lib/neutral/index.mjs +18 -0
- package/dist/lib/neutral/meta.json +1 -0
- package/dist/lib/neutral/meta.mjs +8 -0
- package/dist/lib/neutral/meta.mjs.map +7 -0
- package/dist/lib/neutral/move-RQZ7BJY3.mjs +37 -0
- package/dist/lib/neutral/move-RQZ7BJY3.mjs.map +7 -0
- package/dist/lib/neutral/operation-handler-EKZKFQUG.mjs +13 -0
- package/dist/lib/neutral/operation-handler-EKZKFQUG.mjs.map +7 -0
- package/dist/lib/neutral/operations/index.mjs +8 -0
- package/dist/lib/neutral/operations/index.mjs.map +7 -0
- package/dist/lib/neutral/play-GDGCEPQL.mjs +46 -0
- package/dist/lib/neutral/play-GDGCEPQL.mjs.map +7 -0
- package/dist/lib/neutral/plugin.mjs +16 -0
- package/dist/lib/neutral/plugin.mjs.map +7 -0
- package/dist/lib/neutral/print-ZQA74KZI.mjs +29 -0
- package/dist/lib/neutral/print-ZQA74KZI.mjs.map +7 -0
- package/dist/lib/neutral/testing.mjs +8 -0
- package/dist/lib/neutral/testing.mjs.map +7 -0
- package/dist/lib/neutral/translations.mjs +34 -0
- package/dist/lib/neutral/translations.mjs.map +7 -0
- package/dist/lib/neutral/types/index.mjs +10 -0
- package/dist/lib/neutral/types/index.mjs.map +7 -0
- package/dist/types/src/ChessPlugin.d.ts +3 -1
- package/dist/types/src/ChessPlugin.d.ts.map +1 -1
- package/dist/types/src/ChessPlugin.node.d.ts +8 -0
- package/dist/types/src/ChessPlugin.node.d.ts.map +1 -0
- package/dist/types/src/ChessPlugin.test.d.ts +2 -0
- package/dist/types/src/ChessPlugin.test.d.ts.map +1 -0
- package/dist/types/src/ChessPlugin.workerd.d.ts +4 -0
- package/dist/types/src/ChessPlugin.workerd.d.ts.map +1 -0
- package/dist/types/src/blueprints/chess-blueprint.d.ts +4 -0
- package/dist/types/src/blueprints/chess-blueprint.d.ts.map +1 -0
- package/dist/types/src/blueprints/index.d.ts +2 -0
- package/dist/types/src/blueprints/index.d.ts.map +1 -0
- package/dist/types/src/capabilities/blueprint-definition.d.ts +5 -5
- package/dist/types/src/capabilities/blueprint-definition.d.ts.map +1 -1
- package/dist/types/src/capabilities/game-variant.d.ts +6 -0
- package/dist/types/src/capabilities/game-variant.d.ts.map +1 -0
- package/dist/types/src/capabilities/index.d.ts +5 -4
- package/dist/types/src/capabilities/index.d.ts.map +1 -1
- package/dist/types/src/capabilities/operation-handler.d.ts +6 -0
- package/dist/types/src/capabilities/operation-handler.d.ts.map +1 -0
- package/dist/types/src/components/{Chessboard.d.ts → Chessboard/Chessboard.d.ts} +10 -10
- package/dist/types/src/components/Chessboard/Chessboard.d.ts.map +1 -0
- package/dist/types/src/components/Chessboard/Chessboard.stories.d.ts +57 -0
- package/dist/types/src/components/Chessboard/Chessboard.stories.d.ts.map +1 -0
- package/dist/types/src/components/{Info.d.ts → Chessboard/Info.d.ts} +5 -6
- package/dist/types/src/components/Chessboard/Info.d.ts.map +1 -0
- package/dist/types/src/components/Chessboard/index.d.ts +2 -0
- package/dist/types/src/components/Chessboard/index.d.ts.map +1 -0
- package/dist/types/src/components/Chessboard/types.d.ts +8 -0
- package/dist/types/src/components/Chessboard/types.d.ts.map +1 -0
- package/dist/types/src/components/index.d.ts +0 -1
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/containers/ChessArticle/ChessArticle.d.ts +5 -0
- package/dist/types/src/containers/ChessArticle/ChessArticle.d.ts.map +1 -0
- package/dist/types/src/containers/ChessArticle/ChessArticle.stories.d.ts +56 -0
- package/dist/types/src/containers/ChessArticle/ChessArticle.stories.d.ts.map +1 -0
- package/dist/types/src/containers/ChessArticle/index.d.ts +2 -0
- package/dist/types/src/containers/ChessArticle/index.d.ts.map +1 -0
- package/dist/types/src/containers/ChessCard/ChessCard.d.ts +5 -0
- package/dist/types/src/containers/ChessCard/ChessCard.d.ts.map +1 -0
- package/dist/types/src/{components/Card.stories.d.ts → containers/ChessCard/ChessCard.stories.d.ts} +2 -9
- package/dist/types/src/containers/ChessCard/ChessCard.stories.d.ts.map +1 -0
- package/dist/types/src/containers/ChessCard/index.d.ts +2 -0
- package/dist/types/src/containers/ChessCard/index.d.ts.map +1 -0
- package/dist/types/src/containers/index.d.ts +4 -0
- package/dist/types/src/containers/index.d.ts.map +1 -0
- package/dist/types/src/index.d.ts +1 -4
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/meta.d.ts +2 -2
- package/dist/types/src/meta.d.ts.map +1 -1
- package/dist/types/src/operations/index.d.ts +3 -0
- package/dist/types/src/operations/index.d.ts.map +1 -0
- package/dist/types/src/operations/move.d.ts +5 -0
- package/dist/types/src/operations/move.d.ts.map +1 -0
- package/dist/types/src/operations/play.d.ts +5 -0
- package/dist/types/src/operations/play.d.ts.map +1 -0
- package/dist/types/src/operations/print.d.ts +5 -0
- package/dist/types/src/operations/print.d.ts.map +1 -0
- package/dist/types/src/plugin.d.ts +4 -0
- package/dist/types/src/plugin.d.ts.map +1 -0
- package/dist/types/src/testing.d.ts +2 -0
- package/dist/types/src/testing.d.ts.map +1 -0
- package/dist/types/src/translations.d.ts +32 -22
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types/Chess.d.ts +12 -21
- package/dist/types/src/types/Chess.d.ts.map +1 -1
- package/dist/types/src/types/ChessOperation.d.ts +24 -0
- package/dist/types/src/types/ChessOperation.d.ts.map +1 -0
- package/dist/types/src/types/index.d.ts +1 -1
- package/dist/types/src/types/index.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +115 -60
- package/src/ChessPlugin.node.ts +23 -0
- package/src/ChessPlugin.test.ts +50 -0
- package/src/ChessPlugin.tsx +19 -54
- package/src/ChessPlugin.workerd.ts +18 -0
- package/src/blueprints/chess-blueprint.ts +32 -0
- package/src/blueprints/index.ts +5 -0
- package/src/capabilities/blueprint-definition.ts +11 -28
- package/src/capabilities/game-variant.ts +42 -0
- package/src/capabilities/index.ts +9 -6
- package/src/capabilities/operation-handler.ts +14 -0
- package/src/components/Chessboard/Chessboard.stories.tsx +94 -0
- package/src/components/{Chessboard.tsx → Chessboard/Chessboard.tsx} +34 -31
- package/src/components/{Info.tsx → Chessboard/Info.tsx} +34 -77
- package/src/components/Chessboard/index.ts +5 -0
- package/src/components/Chessboard/types.ts +18 -0
- package/src/components/index.ts +1 -5
- package/src/containers/ChessArticle/ChessArticle.stories.tsx +59 -0
- package/src/containers/ChessArticle/ChessArticle.tsx +108 -0
- package/src/containers/ChessArticle/index.ts +5 -0
- package/src/containers/ChessCard/ChessCard.stories.tsx +47 -0
- package/src/containers/ChessCard/ChessCard.tsx +27 -0
- package/src/containers/ChessCard/index.ts +5 -0
- package/src/containers/index.ts +8 -0
- package/src/index.ts +1 -5
- package/src/meta.ts +5 -3
- package/src/operations/index.ts +11 -0
- package/src/operations/move.ts +36 -0
- package/src/operations/play.ts +45 -0
- package/src/operations/print.ts +28 -0
- package/src/plugin.ts +11 -0
- package/src/testing.ts +7 -0
- package/src/translations.ts +18 -20
- package/src/types/Chess.ts +28 -29
- package/src/types/ChessOperation.ts +85 -0
- package/src/types/index.ts +1 -1
- package/dist/lib/browser/ChessboardContainer-SZMONNHG.mjs +0 -96
- package/dist/lib/browser/ChessboardContainer-SZMONNHG.mjs.map +0 -7
- package/dist/lib/browser/blueprint-definition-FD4TL5EE.mjs +0 -11
- package/dist/lib/browser/chunk-DUO4WTAM.mjs.map +0 -7
- package/dist/lib/browser/chunk-FBLAVAMY.mjs +0 -84
- package/dist/lib/browser/chunk-FBLAVAMY.mjs.map +0 -7
- package/dist/lib/browser/chunk-R6KK3WAS.mjs +0 -294
- package/dist/lib/browser/chunk-R6KK3WAS.mjs.map +0 -7
- package/dist/lib/browser/chunk-TIIGNOGK.mjs +0 -169
- package/dist/lib/browser/chunk-TIIGNOGK.mjs.map +0 -7
- package/dist/lib/browser/chunk-WLXUZMHC.mjs +0 -8
- package/dist/lib/browser/chunk-WLXUZMHC.mjs.map +0 -7
- package/dist/lib/browser/index.mjs +0 -124
- package/dist/lib/browser/index.mjs.map +0 -7
- package/dist/lib/browser/intent-resolver-GXZN2EBT.mjs +0 -25
- package/dist/lib/browser/intent-resolver-GXZN2EBT.mjs.map +0 -7
- package/dist/lib/browser/meta.json +0 -1
- package/dist/lib/browser/react-surface-EVJLBV6U.mjs +0 -38
- package/dist/lib/browser/react-surface-EVJLBV6U.mjs.map +0 -7
- package/dist/lib/browser/types/index.mjs +0 -10
- package/dist/lib/node-esm/ChessboardContainer-GAIIADOA.mjs +0 -97
- package/dist/lib/node-esm/ChessboardContainer-GAIIADOA.mjs.map +0 -7
- package/dist/lib/node-esm/blueprint-definition-O7ZM3HUF.mjs +0 -12
- package/dist/lib/node-esm/chunk-FKRBFLJC.mjs +0 -10
- package/dist/lib/node-esm/chunk-FKRBFLJC.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-IVEIH4ER.mjs +0 -295
- package/dist/lib/node-esm/chunk-IVEIH4ER.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-KNOOJFIR.mjs +0 -29
- package/dist/lib/node-esm/chunk-KNOOJFIR.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-MP3A3AGA.mjs +0 -85
- package/dist/lib/node-esm/chunk-MP3A3AGA.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-RTCAAOLF.mjs +0 -170
- package/dist/lib/node-esm/chunk-RTCAAOLF.mjs.map +0 -7
- package/dist/lib/node-esm/index.mjs +0 -125
- package/dist/lib/node-esm/index.mjs.map +0 -7
- package/dist/lib/node-esm/intent-resolver-HK5L6P6Z.mjs +0 -26
- package/dist/lib/node-esm/intent-resolver-HK5L6P6Z.mjs.map +0 -7
- package/dist/lib/node-esm/meta.json +0 -1
- package/dist/lib/node-esm/react-surface-4PRNWQ2V.mjs +0 -39
- package/dist/lib/node-esm/react-surface-4PRNWQ2V.mjs.map +0 -7
- package/dist/lib/node-esm/types/index.mjs +0 -11
- package/dist/types/src/capabilities/artifact-definition.d.ts +0 -11
- package/dist/types/src/capabilities/artifact-definition.d.ts.map +0 -1
- package/dist/types/src/capabilities/intent-resolver.d.ts +0 -4
- package/dist/types/src/capabilities/intent-resolver.d.ts.map +0 -1
- package/dist/types/src/capabilities/react-surface.d.ts +0 -4
- package/dist/types/src/capabilities/react-surface.d.ts.map +0 -1
- package/dist/types/src/components/Card.stories.d.ts.map +0 -1
- package/dist/types/src/components/Chessboard.d.ts.map +0 -1
- package/dist/types/src/components/Chessboard.stories.d.ts +0 -44
- package/dist/types/src/components/Chessboard.stories.d.ts.map +0 -1
- package/dist/types/src/components/ChessboardArticle.d.ts +0 -7
- package/dist/types/src/components/ChessboardArticle.d.ts.map +0 -1
- package/dist/types/src/components/ChessboardContainer.d.ts +0 -9
- package/dist/types/src/components/ChessboardContainer.d.ts.map +0 -1
- package/dist/types/src/components/Info.d.ts.map +0 -1
- package/dist/types/src/functions/create.d.ts +0 -14
- package/dist/types/src/functions/create.d.ts.map +0 -1
- package/dist/types/src/functions/index.d.ts +0 -4
- package/dist/types/src/functions/index.d.ts.map +0 -1
- package/dist/types/src/functions/move.d.ts +0 -8
- package/dist/types/src/functions/move.d.ts.map +0 -1
- package/dist/types/src/functions/play.d.ts +0 -9
- package/dist/types/src/functions/play.d.ts.map +0 -1
- package/dist/types/src/types/ChessAction.d.ts +0 -24
- package/dist/types/src/types/ChessAction.d.ts.map +0 -1
- package/src/capabilities/artifact-definition.ts +0 -129
- package/src/capabilities/intent-resolver.ts +0 -22
- package/src/capabilities/react-surface.tsx +0 -23
- package/src/components/Card.stories.tsx +0 -66
- package/src/components/Chessboard.stories.tsx +0 -49
- package/src/components/ChessboardArticle.tsx +0 -69
- package/src/components/ChessboardContainer.tsx +0 -44
- package/src/functions/create.ts +0 -32
- package/src/functions/index.ts +0 -7
- package/src/functions/move.ts +0 -45
- package/src/functions/play.ts +0 -55
- package/src/types/ChessAction.ts +0 -19
- /package/dist/lib/{browser/blueprint-definition-FD4TL5EE.mjs.map → neutral/ChessPlugin.mjs.map} +0 -0
- /package/dist/lib/{browser/types → neutral/blueprints}/index.mjs.map +0 -0
- /package/dist/lib/{node-esm/blueprint-definition-O7ZM3HUF.mjs.map → neutral/chunk-J5LGTIGS.mjs.map} +0 -0
- /package/dist/lib/{node-esm/types → neutral}/index.mjs.map +0 -0
|
@@ -2,10 +2,12 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
import { RegistryContext } from '@effect-atom/atom-react';
|
|
5
6
|
import React, {
|
|
6
7
|
type PropsWithChildren,
|
|
7
8
|
forwardRef,
|
|
8
9
|
useCallback,
|
|
10
|
+
useContext,
|
|
9
11
|
useEffect,
|
|
10
12
|
useImperativeHandle,
|
|
11
13
|
useMemo,
|
|
@@ -13,9 +15,10 @@ import React, {
|
|
|
13
15
|
} from 'react';
|
|
14
16
|
|
|
15
17
|
import { addEventListener } from '@dxos/async';
|
|
18
|
+
import { useObject } from '@dxos/echo-react';
|
|
16
19
|
import { type ThemedClassName } from '@dxos/react-ui';
|
|
17
20
|
import {
|
|
18
|
-
ChessModel,
|
|
21
|
+
type ChessModel,
|
|
19
22
|
Gameboard,
|
|
20
23
|
type GameboardRootProps,
|
|
21
24
|
Chessboard as NaturalChessboard,
|
|
@@ -24,33 +27,29 @@ import {
|
|
|
24
27
|
useGameboardContext,
|
|
25
28
|
} from '@dxos/react-ui-gameboard';
|
|
26
29
|
import { useSoundEffect } from '@dxos/react-ui-sfx';
|
|
27
|
-
import { mx } from '@dxos/react-ui-theme';
|
|
28
30
|
|
|
29
|
-
import { type Chess } from '
|
|
31
|
+
import { type Chess } from '#types';
|
|
30
32
|
|
|
31
33
|
import { Info, type InfoProps } from './Info';
|
|
34
|
+
import { ExtendedChessModel } from './types';
|
|
32
35
|
|
|
33
36
|
export interface ChessboardController {
|
|
34
37
|
setMoveNumber(index: number): void;
|
|
35
38
|
}
|
|
36
39
|
|
|
37
|
-
export class ExtendedChessModel extends ChessModel {
|
|
38
|
-
constructor(readonly object: Chess.Game) {
|
|
39
|
-
super();
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
40
|
//
|
|
44
41
|
// Root
|
|
45
42
|
//
|
|
46
43
|
|
|
47
44
|
type RootProps = PropsWithChildren<{
|
|
48
|
-
|
|
45
|
+
state: Chess.State;
|
|
49
46
|
}>;
|
|
50
47
|
|
|
51
|
-
const Root = forwardRef<ChessboardController, RootProps>(({
|
|
52
|
-
const
|
|
48
|
+
const Root = forwardRef<ChessboardController, RootProps>(({ state, children }, forwardedRef) => {
|
|
49
|
+
const registry = useContext(RegistryContext);
|
|
50
|
+
const model = useMemo(() => new ExtendedChessModel(registry, state), [registry]);
|
|
53
51
|
const click = useSoundEffect('Click');
|
|
52
|
+
const [pgn, updatePgn] = useObject(state, 'pgn');
|
|
54
53
|
|
|
55
54
|
// Controller.
|
|
56
55
|
useImperativeHandle(forwardedRef, () => {
|
|
@@ -59,17 +58,21 @@ const Root = forwardRef<ChessboardController, RootProps>(({ game, children }, fo
|
|
|
59
58
|
};
|
|
60
59
|
}, [model]);
|
|
61
60
|
|
|
61
|
+
// TODO(wittjosiah): Rather than useEffect to sync ECHO object to model, create an alternative model implementation.
|
|
62
|
+
// This model would take the ECHO object and derive game state directly from that.
|
|
63
|
+
// Mutation methods would mutate the ECHO object and other state would be derived from that.
|
|
64
|
+
|
|
62
65
|
// External change.
|
|
63
66
|
// NOTE: Warning if user has not interacted with the board.
|
|
64
67
|
useEffect(() => {
|
|
65
|
-
if (model.pgn !== getRawPgn(
|
|
68
|
+
if (model.pgn !== getRawPgn(pgn ?? '')) {
|
|
66
69
|
const silent = model.pgn === '*';
|
|
67
|
-
model.update(
|
|
70
|
+
model.update(pgn);
|
|
68
71
|
if (!silent) {
|
|
69
72
|
void click.play();
|
|
70
73
|
}
|
|
71
74
|
}
|
|
72
|
-
}, [
|
|
75
|
+
}, [pgn]);
|
|
73
76
|
|
|
74
77
|
// Move.
|
|
75
78
|
const handleDrop = useCallback<NonNullable<GameboardRootProps<ChessModel>['onDrop']>>(
|
|
@@ -79,7 +82,7 @@ const Root = forwardRef<ChessboardController, RootProps>(({ game, children }, fo
|
|
|
79
82
|
}
|
|
80
83
|
|
|
81
84
|
void click.play();
|
|
82
|
-
|
|
85
|
+
updatePgn(() => model.pgn);
|
|
83
86
|
return true;
|
|
84
87
|
},
|
|
85
88
|
[model],
|
|
@@ -96,17 +99,13 @@ const Root = forwardRef<ChessboardController, RootProps>(({ game, children }, fo
|
|
|
96
99
|
// Content
|
|
97
100
|
//
|
|
98
101
|
|
|
99
|
-
type Role = 'card--
|
|
102
|
+
type Role = 'card--content';
|
|
100
103
|
|
|
101
104
|
type ContentProps = ThemedClassName<PropsWithChildren<{ role?: Role }>>;
|
|
102
105
|
|
|
103
|
-
const Content = ({ classNames, children
|
|
106
|
+
const Content = ({ classNames, children }: ContentProps) => {
|
|
104
107
|
return (
|
|
105
|
-
<Gameboard.Content
|
|
106
|
-
classNames={mx(classNames, role === 'card--popover' && 'size-container popover-square')}
|
|
107
|
-
grow={!role || role === 'card--extrinsic'}
|
|
108
|
-
contain={!role || role === 'card--extrinsic' || role === 'card--popover'}
|
|
109
|
-
>
|
|
108
|
+
<Gameboard.Content grow contain classNames={classNames}>
|
|
110
109
|
{children}
|
|
111
110
|
</Gameboard.Content>
|
|
112
111
|
);
|
|
@@ -116,10 +115,13 @@ const Content = ({ classNames, children, role }: ContentProps) => {
|
|
|
116
115
|
// Board
|
|
117
116
|
//
|
|
118
117
|
|
|
118
|
+
const BOARD_NAME = 'Chessboard.Board';
|
|
119
|
+
|
|
119
120
|
type BoardProps = NaturalChessboardProps;
|
|
120
121
|
|
|
121
122
|
const Board = (props: BoardProps) => {
|
|
122
|
-
const
|
|
123
|
+
const registry = useContext(RegistryContext);
|
|
124
|
+
const { model } = useGameboardContext<ChessModel>(BOARD_NAME);
|
|
123
125
|
|
|
124
126
|
// Keyboard navigation.
|
|
125
127
|
const ref = useRef<HTMLDivElement>(null);
|
|
@@ -132,6 +134,7 @@ const Board = (props: BoardProps) => {
|
|
|
132
134
|
ref.current.setAttribute('data-arrow-keys', 'all');
|
|
133
135
|
|
|
134
136
|
return addEventListener(ref.current, 'keydown', (ev) => {
|
|
137
|
+
const moveIndex = registry.get(model.moveIndex);
|
|
135
138
|
switch (ev.key) {
|
|
136
139
|
case 'ArrowUp':
|
|
137
140
|
model.setMoveIndex(0);
|
|
@@ -140,23 +143,23 @@ const Board = (props: BoardProps) => {
|
|
|
140
143
|
model.setMoveIndex(model.game.history().length);
|
|
141
144
|
break;
|
|
142
145
|
case 'ArrowLeft':
|
|
143
|
-
if (
|
|
144
|
-
model.setMoveIndex(
|
|
146
|
+
if (moveIndex > 0) {
|
|
147
|
+
model.setMoveIndex(moveIndex - 1);
|
|
145
148
|
}
|
|
146
149
|
break;
|
|
147
150
|
case 'ArrowRight':
|
|
148
|
-
if (
|
|
149
|
-
model.setMoveIndex(
|
|
151
|
+
if (moveIndex < model.game.history().length) {
|
|
152
|
+
model.setMoveIndex(moveIndex + 1);
|
|
150
153
|
}
|
|
151
154
|
break;
|
|
152
155
|
}
|
|
153
156
|
});
|
|
154
|
-
}, [model]);
|
|
157
|
+
}, [registry, model]);
|
|
155
158
|
|
|
156
|
-
return <NaturalChessboard ref={ref}
|
|
159
|
+
return <NaturalChessboard {...props} ref={ref} />;
|
|
157
160
|
};
|
|
158
161
|
|
|
159
|
-
Board.displayName =
|
|
162
|
+
Board.displayName = BOARD_NAME;
|
|
160
163
|
|
|
161
164
|
//
|
|
162
165
|
// Chessboard
|
|
@@ -2,17 +2,18 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
+
import { useAtomValue } from '@effect-atom/atom-react';
|
|
5
6
|
import React, { type JSX, type PropsWithChildren, useEffect, useMemo, useRef } from 'react';
|
|
6
7
|
|
|
7
|
-
import {
|
|
8
|
-
import { type SpaceMember, getSpace, useMembers } from '@dxos/react-client/echo';
|
|
9
|
-
import { Icon, IconButton, Select, type ThemedClassName, useTranslation } from '@dxos/react-ui';
|
|
8
|
+
import { Icon, IconButton, type ThemedClassName, useTranslation } from '@dxos/react-ui';
|
|
10
9
|
import { type Player, useGameboardContext } from '@dxos/react-ui-gameboard';
|
|
11
|
-
import { mx } from '@dxos/
|
|
10
|
+
import { mx } from '@dxos/ui-theme';
|
|
12
11
|
|
|
13
|
-
import { meta } from '
|
|
12
|
+
import { meta } from '#meta';
|
|
14
13
|
|
|
15
|
-
import { type ExtendedChessModel } from './
|
|
14
|
+
import { type ExtendedChessModel } from './types';
|
|
15
|
+
|
|
16
|
+
const INFO_NAME = 'Chessboard.Info';
|
|
16
17
|
|
|
17
18
|
export type InfoProps = ThemedClassName<
|
|
18
19
|
{
|
|
@@ -24,13 +25,12 @@ export type InfoProps = ThemedClassName<
|
|
|
24
25
|
|
|
25
26
|
export const Info = ({ classNames, orientation = 'white', onOrientationChange, onClose, ...props }: InfoProps) => {
|
|
26
27
|
const { t } = useTranslation(meta.id);
|
|
27
|
-
const { model } = useGameboardContext<ExtendedChessModel>(
|
|
28
|
-
const members = useMembers(getSpace(model.object)?.key);
|
|
28
|
+
const { model } = useGameboardContext<ExtendedChessModel>(INFO_NAME);
|
|
29
29
|
|
|
30
30
|
return (
|
|
31
31
|
<div
|
|
32
32
|
className={mx(
|
|
33
|
-
'grid grid-rows-[min-content_1fr_min-content]
|
|
33
|
+
'grid grid-rows-[min-content_1fr_min-content] w-full min-w-[18rem] p-2 overflow-hidden bg-group-surface rounded-xs',
|
|
34
34
|
classNames,
|
|
35
35
|
)}
|
|
36
36
|
>
|
|
@@ -39,18 +39,17 @@ export const Info = ({ classNames, orientation = 'white', onOrientationChange, o
|
|
|
39
39
|
player={orientation === 'white' ? 'black' : 'white'}
|
|
40
40
|
icon={
|
|
41
41
|
onClose && (
|
|
42
|
-
<IconButton
|
|
42
|
+
<IconButton
|
|
43
|
+
variant='ghost'
|
|
44
|
+
icon='ph--x--regular'
|
|
45
|
+
iconOnly
|
|
46
|
+
label={t('close-info.button')}
|
|
47
|
+
size={4}
|
|
48
|
+
onClick={onClose}
|
|
49
|
+
/>
|
|
43
50
|
)
|
|
44
51
|
}
|
|
45
|
-
|
|
46
|
-
<PlayerSelector
|
|
47
|
-
value={model.object.players?.[orientation === 'white' ? 'black' : 'white']}
|
|
48
|
-
onValueChange={(value) => {
|
|
49
|
-
model.object.players![orientation === 'white' ? 'black' : 'white'] = value;
|
|
50
|
-
}}
|
|
51
|
-
members={members}
|
|
52
|
-
/>
|
|
53
|
-
</PlayerIndicator>
|
|
52
|
+
/>
|
|
54
53
|
|
|
55
54
|
<History model={model} {...props} />
|
|
56
55
|
|
|
@@ -63,26 +62,18 @@ export const Info = ({ classNames, orientation = 'white', onOrientationChange, o
|
|
|
63
62
|
classNames={mx('transition duration-200 ease-linear', orientation === 'white' && 'rotate-180')}
|
|
64
63
|
icon='ph--arrows-clockwise--regular'
|
|
65
64
|
iconOnly
|
|
66
|
-
label={t('flip
|
|
65
|
+
label={t('flip-board.button')}
|
|
67
66
|
size={4}
|
|
68
67
|
onClick={() => onOrientationChange(orientation === 'white' ? 'black' : 'white')}
|
|
69
68
|
/>
|
|
70
69
|
)
|
|
71
70
|
}
|
|
72
|
-
|
|
73
|
-
<PlayerSelector
|
|
74
|
-
value={model.object.players?.[orientation]}
|
|
75
|
-
onValueChange={(value) => {
|
|
76
|
-
model.object.players![orientation] = value;
|
|
77
|
-
}}
|
|
78
|
-
members={members}
|
|
79
|
-
/>
|
|
80
|
-
</PlayerIndicator>
|
|
71
|
+
/>
|
|
81
72
|
</div>
|
|
82
73
|
);
|
|
83
74
|
};
|
|
84
75
|
|
|
85
|
-
Info.displayName =
|
|
76
|
+
Info.displayName = INFO_NAME;
|
|
86
77
|
|
|
87
78
|
//
|
|
88
79
|
// History
|
|
@@ -97,14 +88,15 @@ type HistoryProps = ThemedClassName<{
|
|
|
97
88
|
|
|
98
89
|
const History = ({ classNames, model, min, max, onSelect }: HistoryProps) => {
|
|
99
90
|
const { t } = useTranslation(meta.id);
|
|
91
|
+
const moveIndex = useAtomValue(model.moveIndex);
|
|
100
92
|
const label = model.game.isGameOver()
|
|
101
93
|
? model.game.isCheckmate()
|
|
102
|
-
? t('game.checkmate
|
|
94
|
+
? t('game.checkmate.label')
|
|
103
95
|
: model.game.isStalemate()
|
|
104
|
-
? t('game.stalemate
|
|
105
|
-
: t('game.draw
|
|
96
|
+
? t('game.stalemate.label')
|
|
97
|
+
: t('game.draw.label')
|
|
106
98
|
: model.game.isCheck()
|
|
107
|
-
? t('game.check
|
|
99
|
+
? t('game.check.label')
|
|
108
100
|
: undefined;
|
|
109
101
|
|
|
110
102
|
const history = model.game.history();
|
|
@@ -130,28 +122,28 @@ const History = ({ classNames, model, min, max, onSelect }: HistoryProps) => {
|
|
|
130
122
|
}, [history.length]);
|
|
131
123
|
|
|
132
124
|
useEffect(() => {
|
|
133
|
-
const div = scrollerRef.current?.querySelector(`[data-index="${
|
|
125
|
+
const div = scrollerRef.current?.querySelector(`[data-index="${moveIndex - 1}"]`);
|
|
134
126
|
scrollerRef.current?.classList.add('scrollbar-none');
|
|
135
127
|
div?.scrollIntoView({ behavior: 'smooth' });
|
|
136
128
|
scrollerRef.current?.classList.remove('scrollbar-none');
|
|
137
|
-
}, [
|
|
129
|
+
}, [moveIndex]);
|
|
138
130
|
|
|
139
131
|
return (
|
|
140
132
|
<div
|
|
141
133
|
ref={scrollerRef}
|
|
142
|
-
className={mx('overflow-y-
|
|
134
|
+
className={mx('overflow-y-auto', classNames)}
|
|
143
135
|
style={{
|
|
144
136
|
minHeight: min === undefined ? 'auto' : `${min * 24}px`,
|
|
145
137
|
maxHeight: max === undefined ? 'auto' : `${max * 24}px`,
|
|
146
138
|
}}
|
|
147
139
|
>
|
|
148
140
|
{moves.map(([a, b], index) => (
|
|
149
|
-
<div key={index} className='grid grid-cols-[3rem_1fr_1fr_1rem] gap-2
|
|
141
|
+
<div key={index} className='grid grid-cols-[3rem_1fr_1fr_1rem] gap-2 ps-4'>
|
|
150
142
|
<div className='content-center text-xs text-subdued'>{index + 1}</div>
|
|
151
143
|
{a && (
|
|
152
144
|
<div
|
|
153
145
|
data-index={a.index}
|
|
154
|
-
className={mx('
|
|
146
|
+
className={mx('ps-2 text-sm cursor-pointer', a.index === moveIndex - 1 && 'bg-primary-500')}
|
|
155
147
|
onClick={() => onSelect?.(a.index + 1)}
|
|
156
148
|
>
|
|
157
149
|
{a.move}
|
|
@@ -160,7 +152,7 @@ const History = ({ classNames, model, min, max, onSelect }: HistoryProps) => {
|
|
|
160
152
|
{b && (
|
|
161
153
|
<div
|
|
162
154
|
data-index={b.index}
|
|
163
|
-
className={mx('
|
|
155
|
+
className={mx('ps-2 text-sm cursor-pointer', b.index === moveIndex - 1 && 'bg-primary-500')}
|
|
164
156
|
onClick={() => onSelect?.(b.index + 1)}
|
|
165
157
|
>
|
|
166
158
|
{b.move}
|
|
@@ -186,12 +178,12 @@ type PlayerIndicatorProps = PropsWithChildren<{
|
|
|
186
178
|
const PlayerIndicator = ({ children, model, player, icon }: PlayerIndicatorProps) => {
|
|
187
179
|
const turn = player === (model.game.turn() === 'w' ? 'white' : 'black');
|
|
188
180
|
return (
|
|
189
|
-
<div className='grid grid-cols-[2rem_1fr_2rem] gap-2
|
|
181
|
+
<div className='grid grid-cols-[2rem_1fr_2rem] gap-2 h-(--dx-rail-size) px-1 flex items-center overflow-hidden'>
|
|
190
182
|
<div className='place-items-center'>
|
|
191
183
|
<Icon
|
|
192
184
|
icon={turn ? 'ph--circle--fill' : 'ph--circle--thin'}
|
|
193
185
|
size={6}
|
|
194
|
-
classNames={mx(turn && (model.game.isCheckmate() ? 'text-
|
|
186
|
+
classNames={mx(turn && (model.game.isCheckmate() ? 'text-error-500' : 'text-success-text'))}
|
|
195
187
|
/>
|
|
196
188
|
</div>
|
|
197
189
|
<div className='truncate overflow-hidden items-center'>{children}</div>
|
|
@@ -199,38 +191,3 @@ const PlayerIndicator = ({ children, model, player, icon }: PlayerIndicatorProps
|
|
|
199
191
|
</div>
|
|
200
192
|
);
|
|
201
193
|
};
|
|
202
|
-
|
|
203
|
-
//
|
|
204
|
-
// PlayerSelector
|
|
205
|
-
//
|
|
206
|
-
|
|
207
|
-
type PlayerSelectorProps = {
|
|
208
|
-
value?: string;
|
|
209
|
-
onValueChange: (player: string) => void;
|
|
210
|
-
members: SpaceMember[];
|
|
211
|
-
};
|
|
212
|
-
|
|
213
|
-
const PlayerSelector = ({ value, onValueChange, members }: PlayerSelectorProps) => {
|
|
214
|
-
const { t } = useTranslation(meta.id);
|
|
215
|
-
return (
|
|
216
|
-
<Select.Root value={value} onValueChange={onValueChange}>
|
|
217
|
-
<Select.TriggerButton placeholder={t('select player button')} />
|
|
218
|
-
<Select.Portal>
|
|
219
|
-
<Select.Content>
|
|
220
|
-
<Select.Viewport>
|
|
221
|
-
{members.map((member) => {
|
|
222
|
-
const memberKey = member.identity.identityKey.toHex();
|
|
223
|
-
const displayName = member.identity?.profile?.displayName || generateName(memberKey);
|
|
224
|
-
return (
|
|
225
|
-
<Select.Option key={memberKey} value={memberKey}>
|
|
226
|
-
{displayName}
|
|
227
|
-
</Select.Option>
|
|
228
|
-
);
|
|
229
|
-
})}
|
|
230
|
-
</Select.Viewport>
|
|
231
|
-
<Select.Arrow />
|
|
232
|
-
</Select.Content>
|
|
233
|
-
</Select.Portal>
|
|
234
|
-
</Select.Root>
|
|
235
|
-
);
|
|
236
|
-
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2024 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { type Registry } from '@effect-atom/atom-react';
|
|
6
|
+
|
|
7
|
+
import { ChessModel } from '@dxos/react-ui-gameboard';
|
|
8
|
+
|
|
9
|
+
import { type Chess } from '#types';
|
|
10
|
+
|
|
11
|
+
export class ExtendedChessModel extends ChessModel {
|
|
12
|
+
constructor(
|
|
13
|
+
registry: Registry.Registry,
|
|
14
|
+
readonly object: Chess.State,
|
|
15
|
+
) {
|
|
16
|
+
super(registry);
|
|
17
|
+
}
|
|
18
|
+
}
|
package/src/components/index.ts
CHANGED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2023 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
|
6
|
+
import React, { useMemo } from 'react';
|
|
7
|
+
|
|
8
|
+
import { type Obj } from '@dxos/echo';
|
|
9
|
+
import { make as makeGame } from '@dxos/plugin-game';
|
|
10
|
+
import { withClientProvider } from '@dxos/react-client/testing';
|
|
11
|
+
import { withLayout, withTheme } from '@dxos/react-ui/testing';
|
|
12
|
+
|
|
13
|
+
import { translations } from '#translations';
|
|
14
|
+
import { Chess } from '#types';
|
|
15
|
+
|
|
16
|
+
import { ChessArticle } from './ChessArticle';
|
|
17
|
+
|
|
18
|
+
type DefaultStoryProps = {
|
|
19
|
+
pgn?: string;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const DefaultStory = ({ pgn }: DefaultStoryProps) => {
|
|
23
|
+
const { game, state } = useMemo(() => {
|
|
24
|
+
const state = Chess.make(pgn ? { pgn } : undefined);
|
|
25
|
+
const game = makeGame({ name: 'Story game', variant: state as Obj.Unknown });
|
|
26
|
+
return { game, state };
|
|
27
|
+
}, [pgn]);
|
|
28
|
+
return <ChessArticle role='article' attendableId='story' game={game} variant={state} />;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const meta = {
|
|
32
|
+
title: 'plugins/plugin-chess/containers/ChessArticle',
|
|
33
|
+
component: DefaultStory,
|
|
34
|
+
decorators: [withTheme(), withLayout({ layout: 'fullscreen' }), withClientProvider({ createIdentity: true })],
|
|
35
|
+
parameters: {
|
|
36
|
+
layout: 'fullscreen',
|
|
37
|
+
translations,
|
|
38
|
+
},
|
|
39
|
+
} satisfies Meta<typeof DefaultStory>;
|
|
40
|
+
|
|
41
|
+
export default meta;
|
|
42
|
+
|
|
43
|
+
type Story = StoryObj<typeof meta>;
|
|
44
|
+
|
|
45
|
+
export const Default: Story = {
|
|
46
|
+
args: {},
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export const EndGame: Story = {
|
|
50
|
+
args: {
|
|
51
|
+
pgn: '1. e4 e5 2. Nf3 Nc6 3. Bc4 Bc5 4. c3 Nf6 5. d4 exd4 6. cxd4 Bb4+ 7. Nc3 d5 8. exd5 Nxd5 9. O-O Be6 10. Qb3 Na5 11. Qa4+ c6 12. Bxd5 Bxc3 13. Bxe6 fxe6 *',
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export const Promption: Story = {
|
|
56
|
+
args: {
|
|
57
|
+
pgn: '1. e4 e5 2. Nf3 Nc6 3. Bc4 Bc5 4. c3 Nf6 5. d4 exd4 6. cxd4 Bb4+ 7. Nc3 d5 8. exd5 Nxd5 9. O-O Be6 10. Qb3 Na5 11. Qa4+ c6 12. Bxd5 Bxc3 13. Bxe6 fxe6 14. d5 Qg5 15. dxe6 Qg4 16. e7 Kf7 17. bxc3 Kg6 *',
|
|
58
|
+
},
|
|
59
|
+
};
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2024 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { Chess as ChessJS } from 'chess.js';
|
|
6
|
+
import React, { useCallback, useRef, useState } from 'react';
|
|
7
|
+
|
|
8
|
+
import { Obj } from '@dxos/echo';
|
|
9
|
+
import { type GameVariantSurfaceProps } from '@dxos/plugin-game';
|
|
10
|
+
import { Panel, Toolbar, useTranslation } from '@dxos/react-ui';
|
|
11
|
+
import { type Player } from '@dxos/react-ui-gameboard';
|
|
12
|
+
import { mx } from '@dxos/ui-theme';
|
|
13
|
+
|
|
14
|
+
import { Chessboard, type ChessboardController, type ChessboardInfoProps } from '#components';
|
|
15
|
+
import { meta } from '#meta';
|
|
16
|
+
import { Chess } from '#types';
|
|
17
|
+
|
|
18
|
+
export type ChessArticleProps = GameVariantSurfaceProps;
|
|
19
|
+
|
|
20
|
+
export const ChessArticle = ({ role, variant }: ChessArticleProps) => {
|
|
21
|
+
const { t } = useTranslation(meta.id);
|
|
22
|
+
const [orientation, setOrientation] = useState<Player>('white');
|
|
23
|
+
const [showInfo, setShowInfo] = useState(true);
|
|
24
|
+
const controller = useRef<ChessboardController>(null);
|
|
25
|
+
|
|
26
|
+
const handleSelect = useCallback<NonNullable<ChessboardInfoProps['onSelect']>>((index) => {
|
|
27
|
+
controller.current?.setMoveNumber(index);
|
|
28
|
+
}, []);
|
|
29
|
+
|
|
30
|
+
const isGameOver = (() => {
|
|
31
|
+
if (!Obj.instanceOf(Chess.State, variant) || (!variant.pgn && !variant.fen)) {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
const chess = new ChessJS();
|
|
36
|
+
if (variant.pgn) {
|
|
37
|
+
chess.loadPgn(variant.pgn);
|
|
38
|
+
} else if (variant.fen) {
|
|
39
|
+
chess.load(variant.fen);
|
|
40
|
+
}
|
|
41
|
+
return chess.isGameOver();
|
|
42
|
+
} catch {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
})();
|
|
46
|
+
|
|
47
|
+
const handleNewGame = useCallback(() => {
|
|
48
|
+
if (!Obj.instanceOf(Chess.State, variant)) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
Obj.update(variant, (variant) => {
|
|
52
|
+
const mutable = variant as Obj.Mutable<typeof variant>;
|
|
53
|
+
mutable.pgn = undefined;
|
|
54
|
+
mutable.fen = undefined;
|
|
55
|
+
});
|
|
56
|
+
}, [variant]);
|
|
57
|
+
|
|
58
|
+
if (!Obj.instanceOf(Chess.State, variant)) {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return (
|
|
63
|
+
<Chessboard.Root state={variant} ref={controller}>
|
|
64
|
+
<Panel.Root role={role} classNames='@container'>
|
|
65
|
+
<Panel.Toolbar asChild>
|
|
66
|
+
<Toolbar.Root>
|
|
67
|
+
{isGameOver && <Toolbar.Button onClick={handleNewGame}>{t('new-game.button')}</Toolbar.Button>}
|
|
68
|
+
<div className='grow' />
|
|
69
|
+
<Toolbar.IconButton
|
|
70
|
+
icon='ph--info--regular'
|
|
71
|
+
iconOnly
|
|
72
|
+
label={t('toggle-info.button')}
|
|
73
|
+
classNames={mx('invisible @4xl:visible')}
|
|
74
|
+
onClick={() => setShowInfo((open) => !open)}
|
|
75
|
+
/>
|
|
76
|
+
</Toolbar.Root>
|
|
77
|
+
</Panel.Toolbar>
|
|
78
|
+
<Panel.Content>
|
|
79
|
+
<div
|
|
80
|
+
className={mx(
|
|
81
|
+
'grid h-full w-full',
|
|
82
|
+
showInfo && '@4xl:grid-cols-[1fr_320px] gap-8',
|
|
83
|
+
role === 'article' && 'p-4',
|
|
84
|
+
role === 'section' && 'aspect-square',
|
|
85
|
+
role === 'section' && showInfo && '@4xl:aspect-auto',
|
|
86
|
+
)}
|
|
87
|
+
>
|
|
88
|
+
<Chessboard.Content>
|
|
89
|
+
<Chessboard.Board classNames='border rounded-xs' orientation={orientation} />
|
|
90
|
+
</Chessboard.Content>
|
|
91
|
+
{showInfo && (
|
|
92
|
+
<div className='hidden @4xl:flex flex-col justify-center items-center overflow-hidden'>
|
|
93
|
+
<Chessboard.Info
|
|
94
|
+
orientation={orientation}
|
|
95
|
+
min={8}
|
|
96
|
+
max={8}
|
|
97
|
+
onOrientationChange={setOrientation}
|
|
98
|
+
onClose={() => setShowInfo(false)}
|
|
99
|
+
onSelect={handleSelect}
|
|
100
|
+
/>
|
|
101
|
+
</div>
|
|
102
|
+
)}
|
|
103
|
+
</div>
|
|
104
|
+
</Panel.Content>
|
|
105
|
+
</Panel.Root>
|
|
106
|
+
</Chessboard.Root>
|
|
107
|
+
);
|
|
108
|
+
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
|
6
|
+
import React, { useMemo } from 'react';
|
|
7
|
+
|
|
8
|
+
import { make as makeGame } from '@dxos/plugin-game';
|
|
9
|
+
import { CardContainer } from '@dxos/react-ui-mosaic/testing';
|
|
10
|
+
import { withLayout, withTheme } from '@dxos/react-ui/testing';
|
|
11
|
+
|
|
12
|
+
import { meta as pluginMeta } from '#meta';
|
|
13
|
+
import { Chess } from '#types';
|
|
14
|
+
|
|
15
|
+
import { ChessCard } from './ChessCard';
|
|
16
|
+
|
|
17
|
+
const SAMPLE_PGN =
|
|
18
|
+
'1. e4 e5 2. Nf3 Nc6 3. Bc4 Bc5 4. c3 Nf6 5. d4 exd4 6. cxd4 Bb4+ 7. Nc3 d5 8. exd5 Nxd5 9. O-O Be6 10. Qb3 Na5 11. Qa4+ c6 12. Bxd5 Bxc3 13. Bxe6 fxe6 14. d5 Qg5 15. dxe6 Qg4 16. e7 Kf7 17. bxc3 Kg6 *';
|
|
19
|
+
|
|
20
|
+
const CardStory = () => {
|
|
21
|
+
const { game, state } = useMemo(() => {
|
|
22
|
+
const state = Chess.make({ pgn: SAMPLE_PGN });
|
|
23
|
+
const game = makeGame({ name: 'Story game', variant: state });
|
|
24
|
+
return { game, state };
|
|
25
|
+
}, []);
|
|
26
|
+
return (
|
|
27
|
+
<CardContainer role='popover' icon={pluginMeta.icon}>
|
|
28
|
+
<ChessCard role='card--content' game={game} variant={state} />
|
|
29
|
+
</CardContainer>
|
|
30
|
+
);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const meta = {
|
|
34
|
+
title: 'plugins/plugin-chess/containers/ChessCard',
|
|
35
|
+
render: () => <CardStory />,
|
|
36
|
+
decorators: [withTheme(), withLayout({ layout: 'column' })],
|
|
37
|
+
parameters: {
|
|
38
|
+
layout: 'fullscreen',
|
|
39
|
+
},
|
|
40
|
+
tags: ['cards'],
|
|
41
|
+
} satisfies Meta;
|
|
42
|
+
|
|
43
|
+
export default meta;
|
|
44
|
+
|
|
45
|
+
type Story = StoryObj<typeof meta>;
|
|
46
|
+
|
|
47
|
+
export const Popover: Story = {};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2024 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import React from 'react';
|
|
6
|
+
|
|
7
|
+
import { Obj } from '@dxos/echo';
|
|
8
|
+
import { type GameVariantSurfaceProps } from '@dxos/plugin-game';
|
|
9
|
+
|
|
10
|
+
import { Chessboard } from '#components';
|
|
11
|
+
import { Chess } from '#types';
|
|
12
|
+
|
|
13
|
+
export type ChessCardProps = GameVariantSurfaceProps;
|
|
14
|
+
|
|
15
|
+
export const ChessCard = ({ variant }: ChessCardProps) => {
|
|
16
|
+
if (!Obj.instanceOf(Chess.State, variant)) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<Chessboard.Root state={variant}>
|
|
22
|
+
<Chessboard.Content>
|
|
23
|
+
<Chessboard.Board />
|
|
24
|
+
</Chessboard.Content>
|
|
25
|
+
</Chessboard.Root>
|
|
26
|
+
);
|
|
27
|
+
};
|