@dxos/plugin-chess 0.8.4-main.a4bbb77 → 0.8.4-main.abd8ff62ef

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.
Files changed (229) hide show
  1. package/dist/lib/browser/blueprints/index.mjs +14 -0
  2. package/dist/lib/browser/chunk-H6SON7WG.mjs +28 -0
  3. package/dist/lib/browser/chunk-H6SON7WG.mjs.map +7 -0
  4. package/dist/lib/browser/chunk-IN3LZ2OO.mjs +62 -0
  5. package/dist/lib/browser/chunk-IN3LZ2OO.mjs.map +7 -0
  6. package/dist/lib/browser/chunk-J5LGTIGS.mjs +10 -0
  7. package/dist/lib/browser/chunk-JYP24G6K.mjs +36 -0
  8. package/dist/lib/browser/chunk-JYP24G6K.mjs.map +7 -0
  9. package/dist/lib/browser/chunk-OBKYFOJA.mjs +110 -0
  10. package/dist/lib/browser/chunk-OBKYFOJA.mjs.map +7 -0
  11. package/dist/lib/browser/create-2ME3FNBX.mjs +24 -0
  12. package/dist/lib/browser/create-2ME3FNBX.mjs.map +7 -0
  13. package/dist/lib/browser/index.mjs +30 -111
  14. package/dist/lib/browser/index.mjs.map +4 -4
  15. package/dist/lib/browser/meta.json +1 -1
  16. package/dist/lib/browser/move-TTMIPD5J.mjs +36 -0
  17. package/dist/lib/browser/move-TTMIPD5J.mjs.map +7 -0
  18. package/dist/lib/browser/operations/index.mjs +19 -0
  19. package/dist/lib/browser/operations/index.mjs.map +7 -0
  20. package/dist/lib/browser/play-GHXPV2T2.mjs +45 -0
  21. package/dist/lib/browser/play-GHXPV2T2.mjs.map +7 -0
  22. package/dist/lib/browser/print-RNAGAOM7.mjs +30 -0
  23. package/dist/lib/browser/print-RNAGAOM7.mjs.map +7 -0
  24. package/dist/lib/browser/translations.mjs +38 -0
  25. package/dist/lib/browser/translations.mjs.map +7 -0
  26. package/dist/lib/browser/types/index.mjs +3 -5
  27. package/dist/lib/node-esm/blueprints/index.mjs +15 -0
  28. package/dist/lib/node-esm/blueprints/index.mjs.map +7 -0
  29. package/dist/lib/node-esm/chunk-4C4GPZTA.mjs +29 -0
  30. package/dist/lib/node-esm/chunk-4C4GPZTA.mjs.map +7 -0
  31. package/dist/lib/node-esm/chunk-G2EHRXHX.mjs +111 -0
  32. package/dist/lib/node-esm/chunk-G2EHRXHX.mjs.map +7 -0
  33. package/dist/lib/node-esm/chunk-HSLMI22Q.mjs +11 -0
  34. package/dist/lib/node-esm/chunk-HSLMI22Q.mjs.map +7 -0
  35. package/dist/lib/node-esm/chunk-NSFPC4IO.mjs +38 -0
  36. package/dist/lib/node-esm/chunk-NSFPC4IO.mjs.map +7 -0
  37. package/dist/lib/node-esm/chunk-OHBKSL2Q.mjs +63 -0
  38. package/dist/lib/node-esm/chunk-OHBKSL2Q.mjs.map +7 -0
  39. package/dist/lib/node-esm/create-CC2P7GPT.mjs +25 -0
  40. package/dist/lib/node-esm/create-CC2P7GPT.mjs.map +7 -0
  41. package/dist/lib/node-esm/index.mjs +30 -111
  42. package/dist/lib/node-esm/index.mjs.map +4 -4
  43. package/dist/lib/node-esm/meta.json +1 -1
  44. package/dist/lib/node-esm/move-CYHXWHHM.mjs +37 -0
  45. package/dist/lib/node-esm/move-CYHXWHHM.mjs.map +7 -0
  46. package/dist/lib/node-esm/operations/index.mjs +20 -0
  47. package/dist/lib/node-esm/operations/index.mjs.map +7 -0
  48. package/dist/lib/node-esm/play-KTNK2PBL.mjs +46 -0
  49. package/dist/lib/node-esm/play-KTNK2PBL.mjs.map +7 -0
  50. package/dist/lib/node-esm/print-P23VKVNU.mjs +31 -0
  51. package/dist/lib/node-esm/print-P23VKVNU.mjs.map +7 -0
  52. package/dist/lib/node-esm/translations.mjs +39 -0
  53. package/dist/lib/node-esm/translations.mjs.map +7 -0
  54. package/dist/lib/node-esm/types/index.mjs +3 -5
  55. package/dist/types/src/ChessPlugin.d.ts +3 -1
  56. package/dist/types/src/ChessPlugin.d.ts.map +1 -1
  57. package/dist/types/src/ChessPlugin.node.d.ts +4 -0
  58. package/dist/types/src/ChessPlugin.node.d.ts.map +1 -0
  59. package/dist/types/src/ChessPlugin.test.d.ts +2 -0
  60. package/dist/types/src/ChessPlugin.test.d.ts.map +1 -0
  61. package/dist/types/src/blueprints/chess-blueprint.d.ts +4 -0
  62. package/dist/types/src/blueprints/chess-blueprint.d.ts.map +1 -0
  63. package/dist/types/src/blueprints/index.d.ts +3 -0
  64. package/dist/types/src/blueprints/index.d.ts.map +1 -0
  65. package/dist/types/src/capabilities/artifact-definition.d.ts +3 -2
  66. package/dist/types/src/capabilities/artifact-definition.d.ts.map +1 -1
  67. package/dist/types/src/capabilities/blueprint-definition.d.ts +5 -5
  68. package/dist/types/src/capabilities/blueprint-definition.d.ts.map +1 -1
  69. package/dist/types/src/capabilities/index.d.ts +5 -4
  70. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  71. package/dist/types/src/capabilities/node.d.ts +5 -0
  72. package/dist/types/src/capabilities/node.d.ts.map +1 -0
  73. package/dist/types/src/capabilities/operation-handler.d.ts +6 -0
  74. package/dist/types/src/capabilities/operation-handler.d.ts.map +1 -0
  75. package/dist/types/src/capabilities/react-surface.d.ts +3 -2
  76. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  77. package/dist/types/src/components/{Chessboard.d.ts → Chessboard/Chessboard.d.ts} +8 -8
  78. package/dist/types/src/components/Chessboard/Chessboard.d.ts.map +1 -0
  79. package/dist/types/src/components/Chessboard/Chessboard.stories.d.ts +65 -0
  80. package/dist/types/src/components/Chessboard/Chessboard.stories.d.ts.map +1 -0
  81. package/dist/types/src/components/{Info.d.ts → Chessboard/Info.d.ts} +5 -6
  82. package/dist/types/src/components/Chessboard/Info.d.ts.map +1 -0
  83. package/dist/types/src/components/Chessboard/index.d.ts +2 -0
  84. package/dist/types/src/components/Chessboard/index.d.ts.map +1 -0
  85. package/dist/types/src/components/Chessboard/types.d.ts +8 -0
  86. package/dist/types/src/components/Chessboard/types.d.ts.map +1 -0
  87. package/dist/types/src/components/index.d.ts +0 -1
  88. package/dist/types/src/components/index.d.ts.map +1 -1
  89. package/dist/types/src/containers/ChessArticle/ChessArticle.d.ts +6 -0
  90. package/dist/types/src/containers/ChessArticle/ChessArticle.d.ts.map +1 -0
  91. package/dist/types/src/containers/ChessArticle/ChessArticle.stories.d.ts +64 -0
  92. package/dist/types/src/containers/ChessArticle/ChessArticle.stories.d.ts.map +1 -0
  93. package/dist/types/src/containers/ChessArticle/index.d.ts +2 -0
  94. package/dist/types/src/containers/ChessArticle/index.d.ts.map +1 -0
  95. package/dist/types/src/containers/ChessCard/ChessCard.d.ts +6 -0
  96. package/dist/types/src/containers/ChessCard/ChessCard.d.ts.map +1 -0
  97. package/dist/types/src/containers/ChessCard/ChessCard.stories.d.ts +15 -0
  98. package/dist/types/src/containers/ChessCard/ChessCard.stories.d.ts.map +1 -0
  99. package/dist/types/src/containers/ChessCard/index.d.ts +2 -0
  100. package/dist/types/src/containers/ChessCard/index.d.ts.map +1 -0
  101. package/dist/types/src/containers/index.d.ts +4 -0
  102. package/dist/types/src/containers/index.d.ts.map +1 -0
  103. package/dist/types/src/index.d.ts +3 -4
  104. package/dist/types/src/index.d.ts.map +1 -1
  105. package/dist/types/src/meta.d.ts +2 -2
  106. package/dist/types/src/meta.d.ts.map +1 -1
  107. package/dist/types/src/operations/create.d.ts +5 -0
  108. package/dist/types/src/operations/create.d.ts.map +1 -0
  109. package/dist/types/src/operations/definitions.d.ts +51 -0
  110. package/dist/types/src/operations/definitions.d.ts.map +1 -0
  111. package/dist/types/src/operations/index.d.ts +4 -0
  112. package/dist/types/src/operations/index.d.ts.map +1 -0
  113. package/dist/types/src/operations/move.d.ts +5 -0
  114. package/dist/types/src/operations/move.d.ts.map +1 -0
  115. package/dist/types/src/operations/play.d.ts +5 -0
  116. package/dist/types/src/operations/play.d.ts.map +1 -0
  117. package/dist/types/src/operations/print.d.ts +5 -0
  118. package/dist/types/src/operations/print.d.ts.map +1 -0
  119. package/dist/types/src/translations.d.ts +40 -22
  120. package/dist/types/src/translations.d.ts.map +1 -1
  121. package/dist/types/src/types/Chess.d.ts +19 -19
  122. package/dist/types/src/types/Chess.d.ts.map +1 -1
  123. package/dist/types/src/types/index.d.ts +0 -1
  124. package/dist/types/src/types/index.d.ts.map +1 -1
  125. package/dist/types/tsconfig.tsbuildinfo +1 -1
  126. package/package.json +83 -51
  127. package/src/ChessPlugin.node.ts +45 -0
  128. package/src/ChessPlugin.test.ts +49 -0
  129. package/src/ChessPlugin.tsx +43 -53
  130. package/src/blueprints/chess-blueprint.ts +34 -0
  131. package/src/blueprints/index.ts +6 -0
  132. package/src/capabilities/artifact-definition.ts +100 -93
  133. package/src/capabilities/blueprint-definition.ts +11 -28
  134. package/src/capabilities/index.ts +9 -6
  135. package/src/capabilities/node.ts +16 -0
  136. package/src/capabilities/operation-handler.ts +14 -0
  137. package/src/capabilities/react-surface.tsx +27 -15
  138. package/src/components/Chessboard/Chessboard.stories.tsx +94 -0
  139. package/src/components/{Chessboard.tsx → Chessboard/Chessboard.tsx} +32 -29
  140. package/src/components/{Info.tsx → Chessboard/Info.tsx} +42 -25
  141. package/src/components/Chessboard/index.ts +5 -0
  142. package/src/components/Chessboard/types.ts +18 -0
  143. package/src/components/index.ts +1 -5
  144. package/src/containers/ChessArticle/ChessArticle.stories.tsx +53 -0
  145. package/src/containers/ChessArticle/ChessArticle.tsx +73 -0
  146. package/src/containers/ChessArticle/index.ts +5 -0
  147. package/src/containers/ChessCard/ChessCard.stories.tsx +42 -0
  148. package/src/containers/ChessCard/ChessCard.tsx +22 -0
  149. package/src/containers/ChessCard/index.ts +5 -0
  150. package/src/containers/index.ts +8 -0
  151. package/src/index.ts +6 -4
  152. package/src/meta.ts +6 -4
  153. package/src/operations/create.ts +21 -0
  154. package/src/operations/definitions.ts +109 -0
  155. package/src/operations/index.ts +16 -0
  156. package/src/operations/move.ts +36 -0
  157. package/src/operations/play.ts +45 -0
  158. package/src/operations/print.ts +28 -0
  159. package/src/translations.ts +21 -19
  160. package/src/types/Chess.ts +30 -34
  161. package/src/types/index.ts +0 -1
  162. package/dist/lib/browser/ChessboardContainer-JOCAWL5W.mjs +0 -97
  163. package/dist/lib/browser/ChessboardContainer-JOCAWL5W.mjs.map +0 -7
  164. package/dist/lib/browser/blueprint-definition-LC4GNYMG.mjs +0 -11
  165. package/dist/lib/browser/chunk-2EN3CBLB.mjs +0 -8
  166. package/dist/lib/browser/chunk-2EN3CBLB.mjs.map +0 -7
  167. package/dist/lib/browser/chunk-3WEALY7P.mjs +0 -84
  168. package/dist/lib/browser/chunk-3WEALY7P.mjs.map +0 -7
  169. package/dist/lib/browser/chunk-4ULSTPL6.mjs +0 -166
  170. package/dist/lib/browser/chunk-4ULSTPL6.mjs.map +0 -7
  171. package/dist/lib/browser/chunk-NR4YFUK7.mjs +0 -306
  172. package/dist/lib/browser/chunk-NR4YFUK7.mjs.map +0 -7
  173. package/dist/lib/browser/chunk-WSUUPPDK.mjs +0 -26
  174. package/dist/lib/browser/chunk-WSUUPPDK.mjs.map +0 -7
  175. package/dist/lib/browser/intent-resolver-PMP36Y5B.mjs +0 -25
  176. package/dist/lib/browser/intent-resolver-PMP36Y5B.mjs.map +0 -7
  177. package/dist/lib/browser/react-surface-TSLFLTXN.mjs +0 -38
  178. package/dist/lib/browser/react-surface-TSLFLTXN.mjs.map +0 -7
  179. package/dist/lib/node-esm/ChessboardContainer-XAVVBRFW.mjs +0 -98
  180. package/dist/lib/node-esm/ChessboardContainer-XAVVBRFW.mjs.map +0 -7
  181. package/dist/lib/node-esm/blueprint-definition-FBGRWYEW.mjs +0 -12
  182. package/dist/lib/node-esm/chunk-5C2OYL2B.mjs +0 -27
  183. package/dist/lib/node-esm/chunk-5C2OYL2B.mjs.map +0 -7
  184. package/dist/lib/node-esm/chunk-7PHZFXU5.mjs +0 -10
  185. package/dist/lib/node-esm/chunk-7PHZFXU5.mjs.map +0 -7
  186. package/dist/lib/node-esm/chunk-AR3TI5LX.mjs +0 -167
  187. package/dist/lib/node-esm/chunk-AR3TI5LX.mjs.map +0 -7
  188. package/dist/lib/node-esm/chunk-LMXETYDF.mjs +0 -85
  189. package/dist/lib/node-esm/chunk-LMXETYDF.mjs.map +0 -7
  190. package/dist/lib/node-esm/chunk-VVTQFCUK.mjs +0 -307
  191. package/dist/lib/node-esm/chunk-VVTQFCUK.mjs.map +0 -7
  192. package/dist/lib/node-esm/intent-resolver-5P7Y2ZKB.mjs +0 -26
  193. package/dist/lib/node-esm/intent-resolver-5P7Y2ZKB.mjs.map +0 -7
  194. package/dist/lib/node-esm/react-surface-AN4SMEDU.mjs +0 -39
  195. package/dist/lib/node-esm/react-surface-AN4SMEDU.mjs.map +0 -7
  196. package/dist/types/src/capabilities/intent-resolver.d.ts +0 -4
  197. package/dist/types/src/capabilities/intent-resolver.d.ts.map +0 -1
  198. package/dist/types/src/components/Card.stories.d.ts +0 -13
  199. package/dist/types/src/components/Card.stories.d.ts.map +0 -1
  200. package/dist/types/src/components/Chessboard.d.ts.map +0 -1
  201. package/dist/types/src/components/Chessboard.stories.d.ts +0 -44
  202. package/dist/types/src/components/Chessboard.stories.d.ts.map +0 -1
  203. package/dist/types/src/components/ChessboardArticle.d.ts +0 -7
  204. package/dist/types/src/components/ChessboardArticle.d.ts.map +0 -1
  205. package/dist/types/src/components/ChessboardContainer.d.ts +0 -9
  206. package/dist/types/src/components/ChessboardContainer.d.ts.map +0 -1
  207. package/dist/types/src/components/Info.d.ts.map +0 -1
  208. package/dist/types/src/functions/create.d.ts +0 -14
  209. package/dist/types/src/functions/create.d.ts.map +0 -1
  210. package/dist/types/src/functions/index.d.ts +0 -4
  211. package/dist/types/src/functions/index.d.ts.map +0 -1
  212. package/dist/types/src/functions/move.d.ts +0 -8
  213. package/dist/types/src/functions/move.d.ts.map +0 -1
  214. package/dist/types/src/functions/play.d.ts +0 -9
  215. package/dist/types/src/functions/play.d.ts.map +0 -1
  216. package/dist/types/src/types/ChessAction.d.ts +0 -24
  217. package/dist/types/src/types/ChessAction.d.ts.map +0 -1
  218. package/src/capabilities/intent-resolver.ts +0 -22
  219. package/src/components/Card.stories.tsx +0 -66
  220. package/src/components/Chessboard.stories.tsx +0 -49
  221. package/src/components/ChessboardArticle.tsx +0 -69
  222. package/src/components/ChessboardContainer.tsx +0 -44
  223. package/src/functions/create.ts +0 -31
  224. package/src/functions/index.ts +0 -7
  225. package/src/functions/move.ts +0 -44
  226. package/src/functions/play.ts +0 -54
  227. package/src/types/ChessAction.ts +0 -19
  228. /package/dist/lib/browser/{blueprint-definition-LC4GNYMG.mjs.map → blueprints/index.mjs.map} +0 -0
  229. /package/dist/lib/{node-esm/blueprint-definition-FBGRWYEW.mjs.map → browser/chunk-J5LGTIGS.mjs.map} +0 -0
@@ -2,35 +2,18 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { Capabilities, contributes } from '@dxos/app-framework';
6
- import { Blueprint, Template } from '@dxos/blueprints';
7
- import { type FunctionDefinition } from '@dxos/functions';
8
- import { trim } from '@dxos/util';
5
+ import * as Effect from 'effect/Effect';
9
6
 
10
- import { create, move, play } from '../functions';
7
+ import { Capability } from '@dxos/app-framework';
8
+ import { AppCapabilities } from '@dxos/app-toolkit';
9
+ // eslint-disable-next-line unused-imports/no-unused-imports
10
+ import type { Blueprint } from '@dxos/compute';
11
11
 
12
- export const BLUEPRINT_KEY = 'dxos.org/blueprint/chess';
12
+ import { ChessBlueprint } from '#blueprints';
13
13
 
14
- const functions: FunctionDefinition[] = [create, move, play];
14
+ const blueprintDefinition = Capability.makeModule<
15
+ [],
16
+ Capability.Capability<typeof AppCapabilities.BlueprintDefinition>[]
17
+ >(() => Effect.succeed([Capability.contributes(AppCapabilities.BlueprintDefinition, ChessBlueprint)]));
15
18
 
16
- export default () => {
17
- return [
18
- contributes(Capabilities.Functions, functions),
19
- contributes(
20
- Capabilities.BlueprintDefinition,
21
- Blueprint.make({
22
- key: BLUEPRINT_KEY,
23
- name: 'Chess',
24
- tools: Blueprint.toolDefinitions({ functions }),
25
- instructions: Template.make({
26
- source: trim`
27
- You are an expert chess player.
28
- To analyze a game you can access the "pgn" property by loading the context object that represents the current game.
29
- You could suggest a good next move or offer to play a move.
30
- Don't actually make a move unless you are asked to.
31
- `,
32
- }),
33
- }),
34
- ),
35
- ];
36
- };
19
+ export default blueprintDefinition;
@@ -2,10 +2,13 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { lazy } from '@dxos/app-framework';
5
+ import { Capability } from '@dxos/app-framework';
6
+ // eslint-disable-next-line unused-imports/no-unused-imports
7
+ import type { Blueprint, OperationHandlerSet } from '@dxos/compute';
6
8
 
7
- export const BlueprintDefinition = lazy(() => import('./blueprint-definition'));
8
- export const IntentResolver = lazy(() => import('./intent-resolver'));
9
- export const ReactSurface = lazy(() => import('./react-surface'));
10
-
11
- export * from './blueprint-definition';
9
+ export const BlueprintDefinition = Capability.lazy('BlueprintDefinition', () => import('./blueprint-definition'));
10
+ export const OperationHandler = Capability.lazy<OperationHandlerSet.OperationHandlerSet>(
11
+ 'OperationHandler',
12
+ () => import('./operation-handler'),
13
+ );
14
+ export const ReactSurface = Capability.lazy('ReactSurface', () => import('./react-surface'));
@@ -0,0 +1,16 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { Capability } from '@dxos/app-framework';
6
+ import { OperationHandlerSet } from '@dxos/compute';
7
+
8
+ export const BlueprintDefinition = Capability.lazy<[], Capability.Any[]>(
9
+ 'BlueprintDefinition',
10
+ () => import('./blueprint-definition'),
11
+ );
12
+
13
+ export const OperationHandler = Capability.lazy<OperationHandlerSet.OperationHandlerSet>(
14
+ 'OperationHandler',
15
+ () => import('./operation-handler'),
16
+ );
@@ -0,0 +1,14 @@
1
+ // Copyright 2025 DXOS.org
2
+
3
+ import * as Effect from 'effect/Effect';
4
+
5
+ import { Capabilities, Capability } from '@dxos/app-framework';
6
+ import type { OperationHandlerSet } from '@dxos/compute';
7
+
8
+ import { ChessHandlers } from '#operations';
9
+
10
+ export default Capability.makeModule<OperationHandlerSet.OperationHandlerSet>(
11
+ Effect.fnUntraced(function* () {
12
+ return Capability.contributes(Capabilities.OperationHandler, ChessHandlers);
13
+ }),
14
+ );
@@ -2,22 +2,34 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
+ import * as Effect from 'effect/Effect';
5
6
  import React from 'react';
6
7
 
7
- import { Capabilities, contributes, createSurface } from '@dxos/app-framework';
8
- import { Obj } from '@dxos/echo';
8
+ import { Capabilities, Capability } from '@dxos/app-framework';
9
+ import { Surface } from '@dxos/app-framework/ui';
10
+ import { AppSurface } from '@dxos/app-toolkit/ui';
9
11
 
10
- import { ChessboardContainer } from '../components';
11
- import { meta } from '../meta';
12
- import { Chess } from '../types';
12
+ import { ChessArticle, ChessCard } from '#containers';
13
+ import { Chess } from '#types';
13
14
 
14
- export default () =>
15
- contributes(Capabilities.ReactSurface, [
16
- createSurface({
17
- id: meta.id,
18
- role: ['article', 'section', 'card--intrinsic', 'card--extrinsic', 'card--popover', 'card--transclusion'],
19
- // TODO(burdon): Could this be standardized so that we don't require a subject property.
20
- filter: (data): data is { subject: Chess.Game } => Obj.instanceOf(Chess.Game, data.subject),
21
- component: ({ data, role }) => <ChessboardContainer game={data.subject} role={role} />,
22
- }),
23
- ]);
15
+ export default Capability.makeModule(() =>
16
+ Effect.succeed(
17
+ Capability.contributes(Capabilities.ReactSurface, [
18
+ Surface.create({
19
+ id: 'game',
20
+ filter: AppSurface.oneOf(
21
+ AppSurface.object(AppSurface.Article, Chess.Game),
22
+ AppSurface.object(AppSurface.Section, Chess.Game),
23
+ ),
24
+ component: ({ data, role }) => (
25
+ <ChessArticle role={role} subject={data.subject} attendableId={data.attendableId} />
26
+ ),
27
+ }),
28
+ Surface.create({
29
+ id: 'game-card',
30
+ filter: AppSurface.object(AppSurface.Card, Chess.Game),
31
+ component: ({ data, role }) => <ChessCard role={role} subject={data.subject} />,
32
+ }),
33
+ ]),
34
+ ),
35
+ );
@@ -0,0 +1,94 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import { type Meta, type StoryObj } from '@storybook/react-vite';
6
+ import React, { useCallback, useMemo, useRef, useState } from 'react';
7
+
8
+ import { withClientProvider } from '@dxos/react-client/testing';
9
+ import { type Player } from '@dxos/react-ui-gameboard';
10
+ import { withLayout, withTheme } from '@dxos/react-ui/testing';
11
+
12
+ import { translations } from '#translations';
13
+ import { Chess } from '#types';
14
+
15
+ import { Chessboard, type ChessboardController, type ChessboardInfoProps } from './Chessboard';
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 *';
19
+
20
+ const PROMOTION_PGN =
21
+ '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 Kf8 16. e7+ Kg8 *';
22
+
23
+ type DefaultStoryProps = {
24
+ pgn?: string;
25
+ };
26
+
27
+ const DefaultStory = ({ pgn }: DefaultStoryProps) => {
28
+ const game = useMemo(() => Chess.make(pgn ? { pgn } : undefined), [pgn]);
29
+ const [orientation, setOrientation] = useState<Player>('white');
30
+ const [showInfo, setShowInfo] = useState(true);
31
+ const controller = useRef<ChessboardController>(null);
32
+
33
+ const handleSelect = useCallback<NonNullable<ChessboardInfoProps['onSelect']>>((index) => {
34
+ controller.current?.setMoveNumber(index);
35
+ }, []);
36
+
37
+ return (
38
+ <Chessboard.Root game={game} ref={controller}>
39
+ <div className='flex h-full w-full gap-4 p-4 overflow-hidden'>
40
+ <Chessboard.Content classNames='grow'>
41
+ <Chessboard.Board classNames='border rounded-xs' orientation={orientation} />
42
+ </Chessboard.Content>
43
+ {showInfo && (
44
+ <div className='flex flex-col justify-center items-center overflow-hidden'>
45
+ <Chessboard.Info
46
+ orientation={orientation}
47
+ min={8}
48
+ max={8}
49
+ onOrientationChange={setOrientation}
50
+ onClose={() => setShowInfo(false)}
51
+ onSelect={handleSelect}
52
+ />
53
+ </div>
54
+ )}
55
+ </div>
56
+ </Chessboard.Root>
57
+ );
58
+ };
59
+
60
+ const meta = {
61
+ title: 'plugins/plugin-chess/components/Chessboard',
62
+ component: DefaultStory,
63
+ decorators: [withTheme(), withLayout({ layout: 'fullscreen' }), withClientProvider({ createIdentity: true })],
64
+ parameters: {
65
+ layout: 'fullscreen',
66
+ translations,
67
+ },
68
+ } satisfies Meta<typeof DefaultStory>;
69
+
70
+ export default meta;
71
+
72
+ type Story = StoryObj<typeof meta>;
73
+
74
+ export const Default: Story = {
75
+ args: {},
76
+ };
77
+
78
+ export const WithPgn: Story = {
79
+ args: {
80
+ pgn: SAMPLE_PGN,
81
+ },
82
+ };
83
+
84
+ export const Promotion: Story = {
85
+ args: {
86
+ pgn: PROMOTION_PGN,
87
+ },
88
+ };
89
+
90
+ export const NewGame: Story = {
91
+ args: {
92
+ pgn: undefined,
93
+ },
94
+ };
@@ -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,22 +27,16 @@ 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 '../types';
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
  //
@@ -49,8 +46,10 @@ type RootProps = PropsWithChildren<{
49
46
  }>;
50
47
 
51
48
  const Root = forwardRef<ChessboardController, RootProps>(({ game, children }, forwardedRef) => {
52
- const model = useMemo(() => new ExtendedChessModel(game), []);
49
+ const registry = useContext(RegistryContext);
50
+ const model = useMemo(() => new ExtendedChessModel(registry, game), [registry]);
53
51
  const click = useSoundEffect('Click');
52
+ const [pgn, updatePgn] = useObject(game, '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(game.pgn ?? '')) {
68
+ if (model.pgn !== getRawPgn(pgn ?? '')) {
66
69
  const silent = model.pgn === '*';
67
- model.update(game.pgn);
70
+ model.update(pgn);
68
71
  if (!silent) {
69
72
  void click.play();
70
73
  }
71
74
  }
72
- }, [game.pgn]);
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
- game.pgn = model.pgn;
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--popover' | 'card--intrinsic' | 'card--extrinsic';
102
+ type Role = 'card--content';
100
103
 
101
104
  type ContentProps = ThemedClassName<PropsWithChildren<{ role?: Role }>>;
102
105
 
103
- const Content = ({ classNames, children, role }: ContentProps) => {
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 { model } = useGameboardContext<ChessModel>(Board.displayName);
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 (model.moveIndex.value > 0) {
144
- model.setMoveIndex(model.moveIndex.value - 1);
146
+ if (moveIndex > 0) {
147
+ model.setMoveIndex(moveIndex - 1);
145
148
  }
146
149
  break;
147
150
  case 'ArrowRight':
148
- if (model.moveIndex.value < model.game.history().length) {
149
- model.setMoveIndex(model.moveIndex.value + 1);
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} {...props} />;
159
+ return <NaturalChessboard {...props} ref={ref} />;
157
160
  };
158
161
 
159
- Board.displayName = 'Chessboard.Board';
162
+ Board.displayName = BOARD_NAME;
160
163
 
161
164
  //
162
165
  // Chessboard
@@ -2,17 +2,21 @@
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
8
  import { generateName } from '@dxos/display-name';
8
- import { type SpaceMember, getSpace, useMembers } from '@dxos/react-client/echo';
9
+ import { Obj } from '@dxos/echo';
10
+ import { type SpaceMember, useMembers } from '@dxos/react-client/echo';
9
11
  import { Icon, IconButton, Select, type ThemedClassName, useTranslation } from '@dxos/react-ui';
10
12
  import { type Player, useGameboardContext } from '@dxos/react-ui-gameboard';
11
- import { mx } from '@dxos/react-ui-theme';
13
+ import { mx } from '@dxos/ui-theme';
12
14
 
13
- import { meta } from '../meta';
15
+ import { meta } from '#meta';
14
16
 
15
- import { type ExtendedChessModel } from './Chessboard';
17
+ import { type ExtendedChessModel } from './types';
18
+
19
+ const INFO_NAME = 'Chessboard.Info';
16
20
 
17
21
  export type InfoProps = ThemedClassName<
18
22
  {
@@ -24,13 +28,14 @@ export type InfoProps = ThemedClassName<
24
28
 
25
29
  export const Info = ({ classNames, orientation = 'white', onOrientationChange, onClose, ...props }: InfoProps) => {
26
30
  const { t } = useTranslation(meta.id);
27
- const { model } = useGameboardContext<ExtendedChessModel>(Info.displayName);
28
- const members = useMembers(getSpace(model.object)?.key);
31
+ const { model } = useGameboardContext<ExtendedChessModel>(INFO_NAME);
32
+ const db = Obj.getDatabase(model.object);
33
+ const members = useMembers(db?.spaceId);
29
34
 
30
35
  return (
31
36
  <div
32
37
  className={mx(
33
- 'grid grid-rows-[min-content_1fr_min-content] is-full min-is-[18rem] p-2 overflow-hidden bg-groupSurface rounded-sm',
38
+ 'grid grid-rows-[min-content_1fr_min-content] w-full min-w-[18rem] p-2 overflow-hidden bg-group-surface rounded-xs',
34
39
  classNames,
35
40
  )}
36
41
  >
@@ -39,14 +44,23 @@ export const Info = ({ classNames, orientation = 'white', onOrientationChange, o
39
44
  player={orientation === 'white' ? 'black' : 'white'}
40
45
  icon={
41
46
  onClose && (
42
- <IconButton icon='ph--x--regular' iconOnly label={t('close info button')} size={4} onClick={onClose} />
47
+ <IconButton
48
+ variant='ghost'
49
+ icon='ph--x--regular'
50
+ iconOnly
51
+ label={t('close-info.button')}
52
+ size={4}
53
+ onClick={onClose}
54
+ />
43
55
  )
44
56
  }
45
57
  >
46
58
  <PlayerSelector
47
59
  value={model.object.players?.[orientation === 'white' ? 'black' : 'white']}
48
60
  onValueChange={(value) => {
49
- model.object.players![orientation === 'white' ? 'black' : 'white'] = value;
61
+ Obj.update(model.object, (obj) => {
62
+ obj.players![orientation === 'white' ? 'black' : 'white'] = value;
63
+ });
50
64
  }}
51
65
  members={members}
52
66
  />
@@ -63,7 +77,7 @@ export const Info = ({ classNames, orientation = 'white', onOrientationChange, o
63
77
  classNames={mx('transition duration-200 ease-linear', orientation === 'white' && 'rotate-180')}
64
78
  icon='ph--arrows-clockwise--regular'
65
79
  iconOnly
66
- label={t('flip board button')}
80
+ label={t('flip-board.button')}
67
81
  size={4}
68
82
  onClick={() => onOrientationChange(orientation === 'white' ? 'black' : 'white')}
69
83
  />
@@ -73,7 +87,9 @@ export const Info = ({ classNames, orientation = 'white', onOrientationChange, o
73
87
  <PlayerSelector
74
88
  value={model.object.players?.[orientation]}
75
89
  onValueChange={(value) => {
76
- model.object.players![orientation] = value;
90
+ Obj.update(model.object, (obj) => {
91
+ obj.players![orientation] = value;
92
+ });
77
93
  }}
78
94
  members={members}
79
95
  />
@@ -82,7 +98,7 @@ export const Info = ({ classNames, orientation = 'white', onOrientationChange, o
82
98
  );
83
99
  };
84
100
 
85
- Info.displayName = 'Chessboard.Info';
101
+ Info.displayName = INFO_NAME;
86
102
 
87
103
  //
88
104
  // History
@@ -97,14 +113,15 @@ type HistoryProps = ThemedClassName<{
97
113
 
98
114
  const History = ({ classNames, model, min, max, onSelect }: HistoryProps) => {
99
115
  const { t } = useTranslation(meta.id);
116
+ const moveIndex = useAtomValue(model.moveIndex);
100
117
  const label = model.game.isGameOver()
101
118
  ? model.game.isCheckmate()
102
- ? t('game.checkmate')
119
+ ? t('game.checkmate.label')
103
120
  : model.game.isStalemate()
104
- ? t('game.stalemate')
105
- : t('game.draw')
121
+ ? t('game.stalemate.label')
122
+ : t('game.draw.label')
106
123
  : model.game.isCheck()
107
- ? t('game.check')
124
+ ? t('game.check.label')
108
125
  : undefined;
109
126
 
110
127
  const history = model.game.history();
@@ -130,28 +147,28 @@ const History = ({ classNames, model, min, max, onSelect }: HistoryProps) => {
130
147
  }, [history.length]);
131
148
 
132
149
  useEffect(() => {
133
- const div = scrollerRef.current?.querySelector(`[data-index="${model.moveIndex.value - 1}"]`);
150
+ const div = scrollerRef.current?.querySelector(`[data-index="${moveIndex - 1}"]`);
134
151
  scrollerRef.current?.classList.add('scrollbar-none');
135
152
  div?.scrollIntoView({ behavior: 'smooth' });
136
153
  scrollerRef.current?.classList.remove('scrollbar-none');
137
- }, [model.moveIndex.value]);
154
+ }, [moveIndex]);
138
155
 
139
156
  return (
140
157
  <div
141
158
  ref={scrollerRef}
142
- className={mx('overflow-y-scroll', classNames)}
159
+ className={mx('overflow-y-auto', classNames)}
143
160
  style={{
144
161
  minHeight: min === undefined ? 'auto' : `${min * 24}px`,
145
162
  maxHeight: max === undefined ? 'auto' : `${max * 24}px`,
146
163
  }}
147
164
  >
148
165
  {moves.map(([a, b], index) => (
149
- <div key={index} className='grid grid-cols-[3rem_1fr_1fr_1rem] gap-2 pis-4 leading-1'>
166
+ <div key={index} className='grid grid-cols-[3rem_1fr_1fr_1rem] gap-2 ps-4'>
150
167
  <div className='content-center text-xs text-subdued'>{index + 1}</div>
151
168
  {a && (
152
169
  <div
153
170
  data-index={a.index}
154
- className={mx('pis-2 cursor-pointer', a.index === model.moveIndex.value - 1 && 'bg-primary-500')}
171
+ className={mx('ps-2 text-sm cursor-pointer', a.index === moveIndex - 1 && 'bg-primary-500')}
155
172
  onClick={() => onSelect?.(a.index + 1)}
156
173
  >
157
174
  {a.move}
@@ -160,7 +177,7 @@ const History = ({ classNames, model, min, max, onSelect }: HistoryProps) => {
160
177
  {b && (
161
178
  <div
162
179
  data-index={b.index}
163
- className={mx('pis-2 cursor-pointer', b.index === model.moveIndex.value - 1 && 'bg-primary-500')}
180
+ className={mx('ps-2 text-sm cursor-pointer', b.index === moveIndex - 1 && 'bg-primary-500')}
164
181
  onClick={() => onSelect?.(b.index + 1)}
165
182
  >
166
183
  {b.move}
@@ -186,12 +203,12 @@ type PlayerIndicatorProps = PropsWithChildren<{
186
203
  const PlayerIndicator = ({ children, model, player, icon }: PlayerIndicatorProps) => {
187
204
  const turn = player === (model.game.turn() === 'w' ? 'white' : 'black');
188
205
  return (
189
- <div className='grid grid-cols-[2rem_1fr_2rem] gap-2 bs-[--rail-size] pis-1 pie-1 flex items-center overflow-hidden'>
206
+ <div className='grid grid-cols-[2rem_1fr_2rem] gap-2 h-(--dx-rail-size) px-1 flex items-center overflow-hidden'>
190
207
  <div className='place-items-center'>
191
208
  <Icon
192
209
  icon={turn ? 'ph--circle--fill' : 'ph--circle--thin'}
193
210
  size={6}
194
- classNames={mx(turn && (model.game.isCheckmate() ? 'text-red-500' : 'text-green-500'))}
211
+ classNames={mx(turn && (model.game.isCheckmate() ? 'text-error-500' : 'text-success-text'))}
195
212
  />
196
213
  </div>
197
214
  <div className='truncate overflow-hidden items-center'>{children}</div>
@@ -214,7 +231,7 @@ const PlayerSelector = ({ value, onValueChange, members }: PlayerSelectorProps)
214
231
  const { t } = useTranslation(meta.id);
215
232
  return (
216
233
  <Select.Root value={value} onValueChange={onValueChange}>
217
- <Select.TriggerButton placeholder={t('select player button')} />
234
+ <Select.TriggerButton placeholder={t('select-player.button')} />
218
235
  <Select.Portal>
219
236
  <Select.Content>
220
237
  <Select.Viewport>
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ export * from './Chessboard';
@@ -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.Game,
15
+ ) {
16
+ super(registry);
17
+ }
18
+ }
@@ -1,9 +1,5 @@
1
1
  //
2
- // Copyright 2023 DXOS.org
2
+ // Copyright 2026 DXOS.org
3
3
  //
4
4
 
5
- import { lazy } from 'react';
6
-
7
5
  export * from './Chessboard';
8
-
9
- export const ChessboardContainer = lazy(() => import('./ChessboardContainer'));