@dreamboard-games/ui-sdk 0.0.41

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 (533) hide show
  1. package/LICENSE +89 -0
  2. package/NOTICE +1 -0
  3. package/README.md +154 -0
  4. package/dist/components/ActionButton.d.ts +13 -0
  5. package/dist/components/ActionButton.d.ts.map +1 -0
  6. package/dist/components/ActionButton.js +14 -0
  7. package/dist/components/ActionPanel.d.ts +33 -0
  8. package/dist/components/ActionPanel.d.ts.map +1 -0
  9. package/dist/components/ActionPanel.js +148 -0
  10. package/dist/components/Card.d.ts +29 -0
  11. package/dist/components/Card.d.ts.map +1 -0
  12. package/dist/components/Card.js +220 -0
  13. package/dist/components/ChromeSuppressionContext.d.ts +7 -0
  14. package/dist/components/ChromeSuppressionContext.d.ts.map +1 -0
  15. package/dist/components/ChromeSuppressionContext.js +34 -0
  16. package/dist/components/CostDisplay.d.ts +22 -0
  17. package/dist/components/CostDisplay.d.ts.map +1 -0
  18. package/dist/components/CostDisplay.js +41 -0
  19. package/dist/components/DiceRoller.d.ts +30 -0
  20. package/dist/components/DiceRoller.d.ts.map +1 -0
  21. package/dist/components/DiceRoller.js +319 -0
  22. package/dist/components/Drawer.d.ts +19 -0
  23. package/dist/components/Drawer.d.ts.map +1 -0
  24. package/dist/components/Drawer.js +55 -0
  25. package/dist/components/ErrorBoundary.d.ts +24 -0
  26. package/dist/components/ErrorBoundary.d.ts.map +1 -0
  27. package/dist/components/ErrorBoundary.js +37 -0
  28. package/dist/components/GameEndDisplay.d.ts +27 -0
  29. package/dist/components/GameEndDisplay.d.ts.map +1 -0
  30. package/dist/components/GameEndDisplay.js +185 -0
  31. package/dist/components/GameSkeleton.d.ts +12 -0
  32. package/dist/components/GameSkeleton.d.ts.map +1 -0
  33. package/dist/components/GameSkeleton.js +54 -0
  34. package/dist/components/Hand.d.ts +99 -0
  35. package/dist/components/Hand.d.ts.map +1 -0
  36. package/dist/components/Hand.js +162 -0
  37. package/dist/components/HandDock.d.ts +35 -0
  38. package/dist/components/HandDock.d.ts.map +1 -0
  39. package/dist/components/HandDock.js +124 -0
  40. package/dist/components/InteractionForm.d.ts +50 -0
  41. package/dist/components/InteractionForm.d.ts.map +1 -0
  42. package/dist/components/InteractionForm.js +402 -0
  43. package/dist/components/MoreActions.d.ts +49 -0
  44. package/dist/components/MoreActions.d.ts.map +1 -0
  45. package/dist/components/MoreActions.js +64 -0
  46. package/dist/components/PhaseIndicator.d.ts +35 -0
  47. package/dist/components/PhaseIndicator.d.ts.map +1 -0
  48. package/dist/components/PhaseIndicator.js +212 -0
  49. package/dist/components/PlayArea.d.ts +28 -0
  50. package/dist/components/PlayArea.d.ts.map +1 -0
  51. package/dist/components/PlayArea.js +48 -0
  52. package/dist/components/PluginRuntime.d.ts +37 -0
  53. package/dist/components/PluginRuntime.d.ts.map +1 -0
  54. package/dist/components/PluginRuntime.js +47 -0
  55. package/dist/components/PrimaryActionButton.d.ts +98 -0
  56. package/dist/components/PrimaryActionButton.d.ts.map +1 -0
  57. package/dist/components/PrimaryActionButton.js +183 -0
  58. package/dist/components/PrimaryButton.d.ts +20 -0
  59. package/dist/components/PrimaryButton.d.ts.map +1 -0
  60. package/dist/components/PrimaryButton.js +5 -0
  61. package/dist/components/PromptDialogHost.d.ts +15 -0
  62. package/dist/components/PromptDialogHost.d.ts.map +1 -0
  63. package/dist/components/PromptDialogHost.js +22 -0
  64. package/dist/components/ResourceCounter.d.ts +38 -0
  65. package/dist/components/ResourceCounter.d.ts.map +1 -0
  66. package/dist/components/ResourceCounter.js +118 -0
  67. package/dist/components/ThemedButton.d.ts +12 -0
  68. package/dist/components/ThemedButton.d.ts.map +1 -0
  69. package/dist/components/ThemedButton.js +38 -0
  70. package/dist/components/Toast.d.ts +35 -0
  71. package/dist/components/Toast.d.ts.map +1 -0
  72. package/dist/components/Toast.js +116 -0
  73. package/dist/components/board/HexGrid.d.ts +344 -0
  74. package/dist/components/board/HexGrid.d.ts.map +1 -0
  75. package/dist/components/board/HexGrid.js +340 -0
  76. package/dist/components/board/NetworkGraph.d.ts +100 -0
  77. package/dist/components/board/NetworkGraph.d.ts.map +1 -0
  78. package/dist/components/board/NetworkGraph.js +123 -0
  79. package/dist/components/board/SlotSystem.d.ts +71 -0
  80. package/dist/components/board/SlotSystem.d.ts.map +1 -0
  81. package/dist/components/board/SlotSystem.js +87 -0
  82. package/dist/components/board/SquareGrid.d.ts +188 -0
  83. package/dist/components/board/SquareGrid.d.ts.map +1 -0
  84. package/dist/components/board/SquareGrid.js +328 -0
  85. package/dist/components/board/TrackBoard.d.ts +113 -0
  86. package/dist/components/board/TrackBoard.d.ts.map +1 -0
  87. package/dist/components/board/TrackBoard.js +135 -0
  88. package/dist/components/board/ZoneMap.d.ts +88 -0
  89. package/dist/components/board/ZoneMap.d.ts.map +1 -0
  90. package/dist/components/board/ZoneMap.js +133 -0
  91. package/dist/components/board/hex-board-view.d.ts +69 -0
  92. package/dist/components/board/hex-board-view.d.ts.map +1 -0
  93. package/dist/components/board/hex-board-view.js +60 -0
  94. package/dist/components/board/index.d.ts +23 -0
  95. package/dist/components/board/index.d.ts.map +1 -0
  96. package/dist/components/board/index.js +40 -0
  97. package/dist/components/board/interaction-accessibility.d.ts +5 -0
  98. package/dist/components/board/interaction-accessibility.d.ts.map +1 -0
  99. package/dist/components/board/interaction-accessibility.js +13 -0
  100. package/dist/components/board/target-layer.d.ts +13 -0
  101. package/dist/components/board/target-layer.d.ts.map +1 -0
  102. package/dist/components/board/target-layer.js +10 -0
  103. package/dist/components/card-render-content.type-test.d.ts +2 -0
  104. package/dist/components/card-render-content.type-test.d.ts.map +1 -0
  105. package/dist/components/card-render-content.type-test.js +1 -0
  106. package/dist/components/index.d.ts +34 -0
  107. package/dist/components/index.d.ts.map +1 -0
  108. package/dist/components/index.js +35 -0
  109. package/dist/components/interaction-dialog-behavior.d.ts +15 -0
  110. package/dist/components/interaction-dialog-behavior.d.ts.map +1 -0
  111. package/dist/components/interaction-dialog-behavior.js +9 -0
  112. package/dist/components/surfaces/BlockerSurface.d.ts +27 -0
  113. package/dist/components/surfaces/BlockerSurface.d.ts.map +1 -0
  114. package/dist/components/surfaces/BlockerSurface.js +38 -0
  115. package/dist/components/surfaces/BoardSurface.d.ts +77 -0
  116. package/dist/components/surfaces/BoardSurface.d.ts.map +1 -0
  117. package/dist/components/surfaces/BoardSurface.js +180 -0
  118. package/dist/components/surfaces/ChromeSurface.d.ts +29 -0
  119. package/dist/components/surfaces/ChromeSurface.d.ts.map +1 -0
  120. package/dist/components/surfaces/ChromeSurface.js +34 -0
  121. package/dist/components/surfaces/ExhaustivenessAudit.d.ts +32 -0
  122. package/dist/components/surfaces/ExhaustivenessAudit.d.ts.map +1 -0
  123. package/dist/components/surfaces/ExhaustivenessAudit.js +65 -0
  124. package/dist/components/surfaces/InboxSurface.d.ts +40 -0
  125. package/dist/components/surfaces/InboxSurface.d.ts.map +1 -0
  126. package/dist/components/surfaces/InboxSurface.js +99 -0
  127. package/dist/components/surfaces/MarketSurface.d.ts +62 -0
  128. package/dist/components/surfaces/MarketSurface.d.ts.map +1 -0
  129. package/dist/components/surfaces/MarketSurface.js +242 -0
  130. package/dist/components/surfaces/PanelSurface.d.ts +111 -0
  131. package/dist/components/surfaces/PanelSurface.d.ts.map +1 -0
  132. package/dist/components/surfaces/PanelSurface.js +180 -0
  133. package/dist/components/surfaces/PlayerCardsSurface.d.ts +104 -0
  134. package/dist/components/surfaces/PlayerCardsSurface.d.ts.map +1 -0
  135. package/dist/components/surfaces/PlayerCardsSurface.js +178 -0
  136. package/dist/components/surfaces/internal/CardZoneFollowUpForm.d.ts +7 -0
  137. package/dist/components/surfaces/internal/CardZoneFollowUpForm.d.ts.map +1 -0
  138. package/dist/components/surfaces/internal/CardZoneFollowUpForm.js +9 -0
  139. package/dist/components/surfaces/internal/DefaultInteractionButton.d.ts +71 -0
  140. package/dist/components/surfaces/internal/DefaultInteractionButton.d.ts.map +1 -0
  141. package/dist/components/surfaces/internal/DefaultInteractionButton.js +82 -0
  142. package/dist/components/surfaces/internal/useCardZoneInteractions.d.ts +21 -0
  143. package/dist/components/surfaces/internal/useCardZoneInteractions.d.ts.map +1 -0
  144. package/dist/components/surfaces/internal/useCardZoneInteractions.js +202 -0
  145. package/dist/components/surfaces/types.d.ts +59 -0
  146. package/dist/components/surfaces/types.d.ts.map +1 -0
  147. package/dist/components/surfaces/types.js +1 -0
  148. package/dist/context/ClientParamSchemaContext.d.ts +21 -0
  149. package/dist/context/ClientParamSchemaContext.d.ts.map +1 -0
  150. package/dist/context/ClientParamSchemaContext.js +12 -0
  151. package/dist/context/InteractionDraftContext.d.ts +69 -0
  152. package/dist/context/InteractionDraftContext.d.ts.map +1 -0
  153. package/dist/context/InteractionDraftContext.js +145 -0
  154. package/dist/context/PluginSessionContext.d.ts +33 -0
  155. package/dist/context/PluginSessionContext.d.ts.map +1 -0
  156. package/dist/context/PluginSessionContext.js +38 -0
  157. package/dist/context/PluginStateContext.d.ts +116 -0
  158. package/dist/context/PluginStateContext.d.ts.map +1 -0
  159. package/dist/context/PluginStateContext.js +186 -0
  160. package/dist/context/RuntimeContext.d.ts +49 -0
  161. package/dist/context/RuntimeContext.d.ts.map +1 -0
  162. package/dist/context/RuntimeContext.js +67 -0
  163. package/dist/defaults/components.d.ts +52 -0
  164. package/dist/defaults/components.d.ts.map +1 -0
  165. package/dist/defaults/components.js +159 -0
  166. package/dist/defaults/index.d.ts +2 -0
  167. package/dist/defaults/index.d.ts.map +1 -0
  168. package/dist/defaults/index.js +1 -0
  169. package/dist/errors/ValidationError.d.ts +10 -0
  170. package/dist/errors/ValidationError.d.ts.map +1 -0
  171. package/dist/errors/ValidationError.js +23 -0
  172. package/dist/helpers/cards.d.ts +3 -0
  173. package/dist/helpers/cards.d.ts.map +1 -0
  174. package/dist/helpers/cards.js +11 -0
  175. package/dist/helpers/track-board.d.ts +79 -0
  176. package/dist/helpers/track-board.d.ts.map +1 -0
  177. package/dist/helpers/track-board.js +56 -0
  178. package/dist/hooks/useActivePlayers.d.ts +16 -0
  179. package/dist/hooks/useActivePlayers.d.ts.map +1 -0
  180. package/dist/hooks/useActivePlayers.js +17 -0
  181. package/dist/hooks/useBoardInteractions.d.ts +110 -0
  182. package/dist/hooks/useBoardInteractions.d.ts.map +1 -0
  183. package/dist/hooks/useBoardInteractions.js +248 -0
  184. package/dist/hooks/useBoardTopology.d.ts +23 -0
  185. package/dist/hooks/useBoardTopology.d.ts.map +1 -0
  186. package/dist/hooks/useBoardTopology.js +128 -0
  187. package/dist/hooks/useCards.d.ts +3 -0
  188. package/dist/hooks/useCards.d.ts.map +1 -0
  189. package/dist/hooks/useCards.js +5 -0
  190. package/dist/hooks/useGameSelector.d.ts +13 -0
  191. package/dist/hooks/useGameSelector.d.ts.map +1 -0
  192. package/dist/hooks/useGameSelector.js +67 -0
  193. package/dist/hooks/useGameView.d.ts +6 -0
  194. package/dist/hooks/useGameView.d.ts.map +1 -0
  195. package/dist/hooks/useGameView.js +7 -0
  196. package/dist/hooks/useHandLayout.d.ts +120 -0
  197. package/dist/hooks/useHandLayout.d.ts.map +1 -0
  198. package/dist/hooks/useHandLayout.js +235 -0
  199. package/dist/hooks/useHexBoard.d.ts +19 -0
  200. package/dist/hooks/useHexBoard.d.ts.map +1 -0
  201. package/dist/hooks/useHexBoard.js +28 -0
  202. package/dist/hooks/useHexGrid.d.ts +56 -0
  203. package/dist/hooks/useHexGrid.d.ts.map +1 -0
  204. package/dist/hooks/useHexGrid.js +112 -0
  205. package/dist/hooks/useInteractionByKey.d.ts +29 -0
  206. package/dist/hooks/useInteractionByKey.d.ts.map +1 -0
  207. package/dist/hooks/useInteractionByKey.js +263 -0
  208. package/dist/hooks/useInteractionHandle.d.ts +103 -0
  209. package/dist/hooks/useInteractionHandle.d.ts.map +1 -0
  210. package/dist/hooks/useInteractionHandle.js +254 -0
  211. package/dist/hooks/useIsMobile.d.ts +7 -0
  212. package/dist/hooks/useIsMobile.d.ts.map +1 -0
  213. package/dist/hooks/useIsMobile.js +29 -0
  214. package/dist/hooks/useIsMyTurn.d.ts +6 -0
  215. package/dist/hooks/useIsMyTurn.d.ts.map +1 -0
  216. package/dist/hooks/useIsMyTurn.js +11 -0
  217. package/dist/hooks/useLobby.d.ts +28 -0
  218. package/dist/hooks/useLobby.d.ts.map +1 -0
  219. package/dist/hooks/useLobby.js +60 -0
  220. package/dist/hooks/useMe.d.ts +11 -0
  221. package/dist/hooks/useMe.d.ts.map +1 -0
  222. package/dist/hooks/useMe.js +32 -0
  223. package/dist/hooks/usePanZoom.d.ts +113 -0
  224. package/dist/hooks/usePanZoom.d.ts.map +1 -0
  225. package/dist/hooks/usePanZoom.js +165 -0
  226. package/dist/hooks/usePlayerInfo.d.ts +4 -0
  227. package/dist/hooks/usePlayerInfo.d.ts.map +1 -0
  228. package/dist/hooks/usePlayerInfo.js +21 -0
  229. package/dist/hooks/usePlayerTurnOrder.d.ts +15 -0
  230. package/dist/hooks/usePlayerTurnOrder.d.ts.map +1 -0
  231. package/dist/hooks/usePlayerTurnOrder.js +22 -0
  232. package/dist/hooks/usePluginRuntime.d.ts +45 -0
  233. package/dist/hooks/usePluginRuntime.d.ts.map +1 -0
  234. package/dist/hooks/usePluginRuntime.js +92 -0
  235. package/dist/hooks/useSeatInbox.d.ts +22 -0
  236. package/dist/hooks/useSeatInbox.d.ts.map +1 -0
  237. package/dist/hooks/useSeatInbox.js +43 -0
  238. package/dist/hooks/useSimultaneousPhase.d.ts +7 -0
  239. package/dist/hooks/useSimultaneousPhase.d.ts.map +1 -0
  240. package/dist/hooks/useSimultaneousPhase.js +8 -0
  241. package/dist/hooks/useSquareBoard.d.ts +21 -0
  242. package/dist/hooks/useSquareBoard.d.ts.map +1 -0
  243. package/dist/hooks/useSquareBoard.js +67 -0
  244. package/dist/hooks/useSquareGrid.d.ts +96 -0
  245. package/dist/hooks/useSquareGrid.d.ts.map +1 -0
  246. package/dist/hooks/useSquareGrid.js +152 -0
  247. package/dist/index.d.ts +30 -0
  248. package/dist/index.d.ts.map +1 -0
  249. package/dist/index.js +20 -0
  250. package/dist/internal/ui/alert.d.ts +8 -0
  251. package/dist/internal/ui/alert.d.ts.map +1 -0
  252. package/dist/internal/ui/alert.js +11 -0
  253. package/dist/internal/ui/button.d.ts +10 -0
  254. package/dist/internal/ui/button.d.ts.map +1 -0
  255. package/dist/internal/ui/button.js +21 -0
  256. package/dist/internal/ui/dialog.d.ts +16 -0
  257. package/dist/internal/ui/dialog.d.ts.map +1 -0
  258. package/dist/internal/ui/dialog.js +35 -0
  259. package/dist/internal/ui/input.d.ts +3 -0
  260. package/dist/internal/ui/input.d.ts.map +1 -0
  261. package/dist/internal/ui/input.js +5 -0
  262. package/dist/internal/ui/label.d.ts +4 -0
  263. package/dist/internal/ui/label.d.ts.map +1 -0
  264. package/dist/internal/ui/label.js +7 -0
  265. package/dist/internal/ui/select.d.ts +9 -0
  266. package/dist/internal/ui/select.d.ts.map +1 -0
  267. package/dist/internal/ui/select.js +23 -0
  268. package/dist/internal/ui/tooltip.d.ts +7 -0
  269. package/dist/internal/ui/tooltip.d.ts.map +1 -0
  270. package/dist/internal/ui/tooltip.js +16 -0
  271. package/dist/internal/ui/utils.d.ts +3 -0
  272. package/dist/internal/ui/utils.d.ts.map +1 -0
  273. package/dist/internal/ui/utils.js +4 -0
  274. package/dist/internal.d.ts +7 -0
  275. package/dist/internal.d.ts.map +1 -0
  276. package/dist/internal.js +4 -0
  277. package/dist/plugin-styles.css +246 -0
  278. package/dist/primitives/board.d.ts +29 -0
  279. package/dist/primitives/board.d.ts.map +1 -0
  280. package/dist/primitives/board.js +163 -0
  281. package/dist/primitives/game-ui-provider.d.ts +12 -0
  282. package/dist/primitives/game-ui-provider.d.ts.map +1 -0
  283. package/dist/primitives/game-ui-provider.js +7 -0
  284. package/dist/primitives/index.d.ts +8 -0
  285. package/dist/primitives/index.d.ts.map +1 -0
  286. package/dist/primitives/index.js +7 -0
  287. package/dist/primitives/interaction.d.ts +52 -0
  288. package/dist/primitives/interaction.d.ts.map +1 -0
  289. package/dist/primitives/interaction.js +250 -0
  290. package/dist/primitives/phase.d.ts +15 -0
  291. package/dist/primitives/phase.d.ts.map +1 -0
  292. package/dist/primitives/phase.js +18 -0
  293. package/dist/primitives/player-roster.d.ts +64 -0
  294. package/dist/primitives/player-roster.d.ts.map +1 -0
  295. package/dist/primitives/player-roster.js +149 -0
  296. package/dist/primitives/primitive-props.d.ts +15 -0
  297. package/dist/primitives/primitive-props.d.ts.map +1 -0
  298. package/dist/primitives/primitive-props.js +39 -0
  299. package/dist/primitives/prompt.d.ts +44 -0
  300. package/dist/primitives/prompt.d.ts.map +1 -0
  301. package/dist/primitives/prompt.js +101 -0
  302. package/dist/primitives/zone.d.ts +31 -0
  303. package/dist/primitives/zone.d.ts.map +1 -0
  304. package/dist/primitives/zone.js +58 -0
  305. package/dist/reducer.d.ts +21 -0
  306. package/dist/reducer.d.ts.map +1 -0
  307. package/dist/reducer.js +14 -0
  308. package/dist/runtime/createPluginRuntimeAPI.d.ts +67 -0
  309. package/dist/runtime/createPluginRuntimeAPI.d.ts.map +1 -0
  310. package/dist/runtime/createPluginRuntimeAPI.js +419 -0
  311. package/dist/theme/ThemeProvider.d.ts +98 -0
  312. package/dist/theme/ThemeProvider.d.ts.map +1 -0
  313. package/dist/theme/ThemeProvider.js +148 -0
  314. package/dist/theme/board.d.ts +42 -0
  315. package/dist/theme/board.d.ts.map +1 -0
  316. package/dist/theme/board.js +34 -0
  317. package/dist/theme/css-vars.d.ts +31 -0
  318. package/dist/theme/css-vars.d.ts.map +1 -0
  319. package/dist/theme/css-vars.js +88 -0
  320. package/dist/theme/derive.d.ts +66 -0
  321. package/dist/theme/derive.d.ts.map +1 -0
  322. package/dist/theme/derive.js +161 -0
  323. package/dist/theme/index.d.ts +22 -0
  324. package/dist/theme/index.d.ts.map +1 -0
  325. package/dist/theme/index.js +20 -0
  326. package/dist/theme/presets/arcade.d.ts +10 -0
  327. package/dist/theme/presets/arcade.d.ts.map +1 -0
  328. package/dist/theme/presets/arcade.js +257 -0
  329. package/dist/theme/presets/studio.d.ts +10 -0
  330. package/dist/theme/presets/studio.d.ts.map +1 -0
  331. package/dist/theme/presets/studio.js +257 -0
  332. package/dist/theme/presets/tabletop.d.ts +15 -0
  333. package/dist/theme/presets/tabletop.d.ts.map +1 -0
  334. package/dist/theme/presets/tabletop.js +262 -0
  335. package/dist/theme/tokens.d.ts +345 -0
  336. package/dist/theme/tokens.d.ts.map +1 -0
  337. package/dist/theme/tokens.js +57 -0
  338. package/dist/types/player-state.d.ts +337 -0
  339. package/dist/types/player-state.d.ts.map +1 -0
  340. package/dist/types/player-state.js +1 -0
  341. package/dist/types/plugin-state.d.ts +324 -0
  342. package/dist/types/plugin-state.d.ts.map +1 -0
  343. package/dist/types/plugin-state.js +1 -0
  344. package/dist/types/reducer-state.d.ts +10 -0
  345. package/dist/types/reducer-state.d.ts.map +1 -0
  346. package/dist/types/reducer-state.js +1 -0
  347. package/dist/types/runtime-api.d.ts +99 -0
  348. package/dist/types/runtime-api.d.ts.map +1 -0
  349. package/dist/types/runtime-api.js +1 -0
  350. package/dist/types/tiled-board.d.ts +187 -0
  351. package/dist/types/tiled-board.d.ts.map +1 -0
  352. package/dist/types/tiled-board.js +226 -0
  353. package/dist/ui-contract.d.ts +78 -0
  354. package/dist/ui-contract.d.ts.map +1 -0
  355. package/dist/ui-contract.js +15 -0
  356. package/dist/ui-sdk.d.ts +3409 -0
  357. package/dist/utils/interaction-inputs.d.ts +22 -0
  358. package/dist/utils/interaction-inputs.d.ts.map +1 -0
  359. package/dist/utils/interaction-inputs.js +219 -0
  360. package/dist/utils/interaction-labels.d.ts +4 -0
  361. package/dist/utils/interaction-labels.d.ts.map +1 -0
  362. package/dist/utils/interaction-labels.js +18 -0
  363. package/dist/utils/interaction-status.d.ts +15 -0
  364. package/dist/utils/interaction-status.d.ts.map +1 -0
  365. package/dist/utils/interaction-status.js +31 -0
  366. package/package.json +101 -0
  367. package/src/components/ActionButton.tsx +48 -0
  368. package/src/components/ActionPanel.tsx +310 -0
  369. package/src/components/Card.tsx +385 -0
  370. package/src/components/ChromeSuppressionContext.tsx +70 -0
  371. package/src/components/CostDisplay.test.tsx +23 -0
  372. package/src/components/CostDisplay.tsx +145 -0
  373. package/src/components/DiceRoller.tsx +601 -0
  374. package/src/components/Drawer.tsx +179 -0
  375. package/src/components/ErrorBoundary.tsx +119 -0
  376. package/src/components/GameEndDisplay.test.tsx +19 -0
  377. package/src/components/GameEndDisplay.tsx +398 -0
  378. package/src/components/GameSkeleton.tsx +260 -0
  379. package/src/components/Hand.tsx +387 -0
  380. package/src/components/HandDock.tsx +257 -0
  381. package/src/components/InteractionForm.test.tsx +303 -0
  382. package/src/components/InteractionForm.tsx +1029 -0
  383. package/src/components/MoreActions.test.tsx +93 -0
  384. package/src/components/MoreActions.tsx +143 -0
  385. package/src/components/PhaseIndicator.tsx +341 -0
  386. package/src/components/PlayArea.tsx +125 -0
  387. package/src/components/PluginRuntime.tsx +92 -0
  388. package/src/components/PrimaryActionButton.test.tsx +138 -0
  389. package/src/components/PrimaryActionButton.tsx +351 -0
  390. package/src/components/PrimaryButton.tsx +44 -0
  391. package/src/components/PromptDialogHost.tsx +92 -0
  392. package/src/components/ResourceCounter.test.tsx +29 -0
  393. package/src/components/ResourceCounter.tsx +275 -0
  394. package/src/components/ThemedButton.tsx +78 -0
  395. package/src/components/Toast.tsx +251 -0
  396. package/src/components/__fixtures__/ActionButton.fixture.tsx +234 -0
  397. package/src/components/__fixtures__/ActionPanel.fixture.tsx +298 -0
  398. package/src/components/__fixtures__/Card.fixture.tsx +185 -0
  399. package/src/components/__fixtures__/CostDisplay.fixture.tsx +156 -0
  400. package/src/components/__fixtures__/DiceRoller.fixture.tsx +435 -0
  401. package/src/components/__fixtures__/Drawer.fixture.tsx +113 -0
  402. package/src/components/__fixtures__/ErrorBoundary.fixture.tsx +82 -0
  403. package/src/components/__fixtures__/GameEndDisplay.fixture.tsx +188 -0
  404. package/src/components/__fixtures__/GameSkeleton.fixture.tsx +46 -0
  405. package/src/components/__fixtures__/Hand.fixture.tsx +522 -0
  406. package/src/components/__fixtures__/HexGrid.fixture.tsx +1181 -0
  407. package/src/components/__fixtures__/NetworkGraph.fixture.tsx +599 -0
  408. package/src/components/__fixtures__/PhaseIndicator.fixture.tsx +181 -0
  409. package/src/components/__fixtures__/PlayArea.fixture.tsx +221 -0
  410. package/src/components/__fixtures__/ResourceCounter.fixture.tsx +227 -0
  411. package/src/components/__fixtures__/SlotSystem.fixture.tsx +824 -0
  412. package/src/components/__fixtures__/SquareGrid.fixture.tsx +764 -0
  413. package/src/components/__fixtures__/Toast.fixture.tsx +97 -0
  414. package/src/components/__fixtures__/TrackBoard.fixture.tsx +685 -0
  415. package/src/components/__fixtures__/ZoneMap.fixture.tsx +754 -0
  416. package/src/components/board/HexGrid.tsx +1294 -0
  417. package/src/components/board/NetworkGraph.tsx +476 -0
  418. package/src/components/board/SlotSystem.tsx +339 -0
  419. package/src/components/board/SquareGrid.tsx +1165 -0
  420. package/src/components/board/TrackBoard.tsx +496 -0
  421. package/src/components/board/ZoneMap.tsx +448 -0
  422. package/src/components/board/hex-board-view.test.tsx +114 -0
  423. package/src/components/board/hex-board-view.ts +123 -0
  424. package/src/components/board/index.ts +142 -0
  425. package/src/components/board/interaction-accessibility.ts +21 -0
  426. package/src/components/board/target-layer-grids.test.tsx +420 -0
  427. package/src/components/board/target-layer.ts +30 -0
  428. package/src/components/card-render-content.type-test.ts +27 -0
  429. package/src/components/index.ts +208 -0
  430. package/src/components/interaction-dialog-behavior.test.ts +23 -0
  431. package/src/components/interaction-dialog-behavior.ts +22 -0
  432. package/src/components/surfaces/BlockerSurface.test.tsx +158 -0
  433. package/src/components/surfaces/BlockerSurface.tsx +127 -0
  434. package/src/components/surfaces/BoardSurface.tsx +340 -0
  435. package/src/components/surfaces/ChromeSurface.tsx +123 -0
  436. package/src/components/surfaces/ExhaustivenessAudit.tsx +91 -0
  437. package/src/components/surfaces/InboxSurface.test.tsx +149 -0
  438. package/src/components/surfaces/InboxSurface.tsx +245 -0
  439. package/src/components/surfaces/MarketSurface.tsx +544 -0
  440. package/src/components/surfaces/PanelSurface.test.tsx +496 -0
  441. package/src/components/surfaces/PanelSurface.tsx +458 -0
  442. package/src/components/surfaces/PlayerCardsSurface.tsx +525 -0
  443. package/src/components/surfaces/internal/CardZoneFollowUpForm.tsx +35 -0
  444. package/src/components/surfaces/internal/DefaultInteractionButton.tsx +219 -0
  445. package/src/components/surfaces/internal/useCardZoneInteractions.ts +311 -0
  446. package/src/components/surfaces/types.ts +100 -0
  447. package/src/context/ClientParamSchemaContext.tsx +44 -0
  448. package/src/context/InteractionDraftContext.tsx +204 -0
  449. package/src/context/PluginSessionContext.tsx +47 -0
  450. package/src/context/PluginStateContext.tsx +254 -0
  451. package/src/context/RuntimeContext.tsx +96 -0
  452. package/src/defaults/components.tsx +442 -0
  453. package/src/defaults/defaults.test.tsx +230 -0
  454. package/src/defaults/index.ts +1 -0
  455. package/src/errors/ValidationError.ts +29 -0
  456. package/src/helpers/cards.ts +19 -0
  457. package/src/helpers/track-board.ts +211 -0
  458. package/src/hooks/useActivePlayers.ts +19 -0
  459. package/src/hooks/useBoardInteractions.test.tsx +622 -0
  460. package/src/hooks/useBoardInteractions.ts +434 -0
  461. package/src/hooks/useBoardTopology.ts +316 -0
  462. package/src/hooks/useCards.test.tsx +129 -0
  463. package/src/hooks/useCards.ts +10 -0
  464. package/src/hooks/useGameSelector.ts +105 -0
  465. package/src/hooks/useGameView.ts +9 -0
  466. package/src/hooks/useHandLayout.ts +349 -0
  467. package/src/hooks/useHexBoard.ts +74 -0
  468. package/src/hooks/useHexGrid.ts +185 -0
  469. package/src/hooks/useInteractionByKey.ts +349 -0
  470. package/src/hooks/useInteractionHandle.ts +437 -0
  471. package/src/hooks/useIsMobile.ts +35 -0
  472. package/src/hooks/useIsMyTurn.test.tsx +99 -0
  473. package/src/hooks/useIsMyTurn.ts +15 -0
  474. package/src/hooks/useLobby.ts +76 -0
  475. package/src/hooks/useMe.ts +48 -0
  476. package/src/hooks/usePanZoom.ts +278 -0
  477. package/src/hooks/usePlayerInfo.ts +28 -0
  478. package/src/hooks/usePlayerTurnOrder.ts +23 -0
  479. package/src/hooks/usePluginRuntime.test.tsx +102 -0
  480. package/src/hooks/usePluginRuntime.ts +130 -0
  481. package/src/hooks/useSeatInbox.ts +61 -0
  482. package/src/hooks/useSimultaneousPhase.ts +10 -0
  483. package/src/hooks/useSquareBoard.ts +124 -0
  484. package/src/hooks/useSquareGrid.ts +328 -0
  485. package/src/index.test.ts +474 -0
  486. package/src/index.ts +148 -0
  487. package/src/internal/ui/alert.tsx +51 -0
  488. package/src/internal/ui/button.tsx +58 -0
  489. package/src/internal/ui/dialog.tsx +134 -0
  490. package/src/internal/ui/input.tsx +21 -0
  491. package/src/internal/ui/label.tsx +21 -0
  492. package/src/internal/ui/select.tsx +129 -0
  493. package/src/internal/ui/tooltip.tsx +54 -0
  494. package/src/internal/ui/utils.ts +5 -0
  495. package/src/internal.ts +18 -0
  496. package/src/plugin-styles.css +246 -0
  497. package/src/primitives/board.test.tsx +139 -0
  498. package/src/primitives/board.tsx +267 -0
  499. package/src/primitives/game-ui-provider.tsx +35 -0
  500. package/src/primitives/index.ts +83 -0
  501. package/src/primitives/interaction.test.tsx +420 -0
  502. package/src/primitives/interaction.tsx +405 -0
  503. package/src/primitives/phase.test.tsx +82 -0
  504. package/src/primitives/phase.tsx +43 -0
  505. package/src/primitives/player-roster.test.tsx +168 -0
  506. package/src/primitives/player-roster.tsx +301 -0
  507. package/src/primitives/primitive-props.tsx +82 -0
  508. package/src/primitives/prompt.test.tsx +159 -0
  509. package/src/primitives/prompt.tsx +203 -0
  510. package/src/primitives/zone.tsx +113 -0
  511. package/src/reducer.ts +42 -0
  512. package/src/runtime/createPluginRuntimeAPI.ts +605 -0
  513. package/src/theme/ThemeProvider.test.tsx +36 -0
  514. package/src/theme/ThemeProvider.tsx +252 -0
  515. package/src/theme/board.ts +61 -0
  516. package/src/theme/css-vars.ts +105 -0
  517. package/src/theme/derive.ts +240 -0
  518. package/src/theme/index.ts +61 -0
  519. package/src/theme/presets/arcade.ts +261 -0
  520. package/src/theme/presets/studio.ts +261 -0
  521. package/src/theme/presets/tabletop.ts +266 -0
  522. package/src/theme/theme.test.ts +258 -0
  523. package/src/theme/tokens.ts +392 -0
  524. package/src/types/player-state.ts +445 -0
  525. package/src/types/plugin-state.ts +407 -0
  526. package/src/types/reducer-state.ts +24 -0
  527. package/src/types/runtime-api.ts +114 -0
  528. package/src/types/tiled-board.ts +785 -0
  529. package/src/ui-contract.ts +168 -0
  530. package/src/utils/interaction-inputs.test.ts +109 -0
  531. package/src/utils/interaction-inputs.ts +331 -0
  532. package/src/utils/interaction-labels.ts +23 -0
  533. package/src/utils/interaction-status.ts +59 -0
@@ -0,0 +1,48 @@
1
+ import { useMemo } from "react";
2
+ import type { PlayerId } from "@dreamboard/manifest-contract";
3
+ import { usePluginSession } from "../context/PluginSessionContext.js";
4
+ import { useLobby } from "./useLobby.js";
5
+ import type { Player } from "../types/player-state.js";
6
+
7
+ // Re-export for consumers
8
+ export type { Player } from "../types/player-state.js";
9
+
10
+ /**
11
+ * Hook to get information about the player currently being controlled by this user.
12
+ * Returns the currently selected player that the user is controlling.
13
+ *
14
+ * @returns Currently controlled player's info
15
+ * @throws Error if called before session is ready or if player not found in lobby
16
+ */
17
+ export function useMe(): Player {
18
+ const { controllingPlayerId } = usePluginSession();
19
+ const lobby = useLobby();
20
+
21
+ return useMemo(() => {
22
+ if (!controllingPlayerId) {
23
+ throw new Error(
24
+ "useMe: No controlling player available. Ensure session is initialized and user is not a spectator.",
25
+ );
26
+ }
27
+
28
+ if (!lobby) {
29
+ throw new Error(
30
+ "useMe: Lobby state not available. Ensure component is rendered during lobby or game phase.",
31
+ );
32
+ }
33
+
34
+ const seat = lobby.seats.find((s) => s.playerId === controllingPlayerId);
35
+ if (!seat) {
36
+ throw new Error(
37
+ `useMe: Player ${controllingPlayerId} not found in lobby seats. This should not happen.`,
38
+ );
39
+ }
40
+
41
+ return {
42
+ playerId: seat.playerId as PlayerId,
43
+ name: seat.displayName,
44
+ isHost: seat.isHost,
45
+ color: seat.playerColor,
46
+ };
47
+ }, [controllingPlayerId, lobby]);
48
+ }
@@ -0,0 +1,278 @@
1
+ /**
2
+ * usePanZoom hook - Unified pan and zoom gestures using @use-gesture/react
3
+ *
4
+ * Provides a declarative API for pan and zoom interactions on board components.
5
+ * Works with both SVG (via viewBox) and HTML (via CSS transforms) elements.
6
+ *
7
+ * Features:
8
+ * - Single finger/mouse drag for panning
9
+ * - Pinch-to-zoom on touch devices
10
+ * - Mouse wheel zoom on desktop
11
+ * - Configurable zoom limits
12
+ * - Optional momentum/inertia
13
+ *
14
+ * @example SVG usage (NetworkGraph, HexGrid, etc.)
15
+ * ```tsx
16
+ * const { transform, bind, resetTransform } = usePanZoom({
17
+ * enabled: enablePanZoom,
18
+ * minZoom: 0.5,
19
+ * maxZoom: 3,
20
+ * });
21
+ *
22
+ * // Apply to viewBox calculation
23
+ * const viewBoxWidth = contentWidth / transform.zoom;
24
+ * const viewBoxX = baseX - transform.pan.x;
25
+ *
26
+ * <svg {...bind()} style={{ touchAction: 'none' }}>
27
+ * ...
28
+ * </svg>
29
+ * ```
30
+ *
31
+ * @example HTML usage (SlotSystem, etc.)
32
+ * ```tsx
33
+ * const { transform, bind, style } = usePanZoom({
34
+ * enabled: enablePanZoom,
35
+ * mode: 'css',
36
+ * });
37
+ *
38
+ * <div {...bind()} style={{ ...style, touchAction: 'none' }}>
39
+ * ...
40
+ * </div>
41
+ * ```
42
+ */
43
+
44
+ import { useState, useCallback, useEffect, useMemo } from "react";
45
+ import { useGesture, type Handler } from "@use-gesture/react";
46
+
47
+ export interface PanZoomTransform {
48
+ /** Current zoom level (1 = 100%) */
49
+ zoom: number;
50
+ /** Current pan offset */
51
+ pan: { x: number; y: number };
52
+ }
53
+
54
+ export interface UsePanZoomOptions {
55
+ /** Whether pan/zoom is enabled */
56
+ enabled?: boolean;
57
+ /** Initial zoom level */
58
+ initialZoom?: number;
59
+ /** Minimum zoom level */
60
+ minZoom?: number;
61
+ /** Maximum zoom level */
62
+ maxZoom?: number;
63
+ /** Initial pan offset */
64
+ initialPan?: { x: number; y: number };
65
+ /** Transform mode: 'viewbox' for SVG, 'css' for HTML elements */
66
+ mode?: "viewbox" | "css";
67
+ /** Zoom sensitivity for wheel events (default: 0.002) */
68
+ wheelSensitivity?: number;
69
+ /** Called when transform changes */
70
+ onTransformChange?: (transform: PanZoomTransform) => void;
71
+ }
72
+
73
+ /** Type for gesture bind function that returns props to spread on element
74
+ * Note: We omit ref from the return type to avoid conflicts with explicit refs on elements.
75
+ * The gesture library handles its own internal ref binding.
76
+ */
77
+ type GestureBindFunction = () => Omit<React.HTMLAttributes<Element>, "ref">;
78
+
79
+ export interface UsePanZoomReturn {
80
+ /** Current transform state */
81
+ transform: PanZoomTransform;
82
+ /** Gesture handlers to spread on the target element - always returns spreadable props */
83
+ bind: GestureBindFunction;
84
+ /** Reset transform to initial values */
85
+ resetTransform: () => void;
86
+ /** Set zoom programmatically */
87
+ setZoom: (zoom: number) => void;
88
+ /** Set pan programmatically */
89
+ setPan: (pan: { x: number; y: number }) => void;
90
+ /** CSS transform style (for mode: 'css') */
91
+ style: React.CSSProperties;
92
+ /** Whether currently dragging/panning */
93
+ isDragging: boolean;
94
+ /** Whether currently pinching */
95
+ isPinching: boolean;
96
+ }
97
+
98
+ /**
99
+ * Hook for pan and zoom gestures on board components
100
+ */
101
+ export function usePanZoom(options: UsePanZoomOptions = {}): UsePanZoomReturn {
102
+ const {
103
+ enabled = true,
104
+ initialZoom = 1,
105
+ minZoom = 0.5,
106
+ maxZoom = 3,
107
+ initialPan = { x: 0, y: 0 },
108
+ mode = "viewbox",
109
+ wheelSensitivity = 0.002,
110
+ onTransformChange,
111
+ } = options;
112
+
113
+ const [zoom, setZoomState] = useState(initialZoom);
114
+ const [pan, setPanState] = useState(initialPan);
115
+ const [isDragging, setIsDragging] = useState(false);
116
+ const [isPinching, setIsPinching] = useState(false);
117
+
118
+ // Clamp zoom to bounds
119
+ const clampZoom = useCallback(
120
+ (z: number) => Math.min(maxZoom, Math.max(minZoom, z)),
121
+ [minZoom, maxZoom],
122
+ );
123
+
124
+ // Update transform and notify
125
+ const updateTransform = useCallback(
126
+ (newZoom: number, newPan: { x: number; y: number }) => {
127
+ const clampedZoom = clampZoom(newZoom);
128
+ setZoomState(clampedZoom);
129
+ setPanState(newPan);
130
+ onTransformChange?.({ zoom: clampedZoom, pan: newPan });
131
+ },
132
+ [clampZoom, onTransformChange],
133
+ );
134
+
135
+ // Gesture bindings
136
+ const bind = useGesture(
137
+ {
138
+ onDrag: (({
139
+ delta: [dx, dy],
140
+ active,
141
+ pinching,
142
+ }: Parameters<Handler<"drag">>[0]) => {
143
+ if (!enabled || pinching) return;
144
+
145
+ setIsDragging(active);
146
+
147
+ if (active) {
148
+ // For viewbox mode, we invert and scale the delta
149
+ // For CSS mode, we apply directly
150
+ const scaleFactor = mode === "viewbox" ? 1 / zoom : 1;
151
+ setPanState((prev) => ({
152
+ x: prev.x + dx * scaleFactor,
153
+ y: prev.y + dy * scaleFactor,
154
+ }));
155
+ }
156
+ }) as Handler<"drag">,
157
+ onPinch: (({
158
+ offset: [scale],
159
+ active,
160
+ }: Parameters<Handler<"pinch">>[0]) => {
161
+ if (!enabled) return;
162
+
163
+ setIsPinching(active);
164
+
165
+ if (active) {
166
+ const newZoom = clampZoom(scale);
167
+ setZoomState(newZoom);
168
+ onTransformChange?.({ zoom: newZoom, pan });
169
+ }
170
+ }) as Handler<"pinch">,
171
+ onWheel: (({ delta: [, dy], event }: Parameters<Handler<"wheel">>[0]) => {
172
+ if (!enabled) return;
173
+
174
+ event.preventDefault();
175
+ const newZoom = clampZoom(zoom - dy * wheelSensitivity);
176
+ setZoomState(newZoom);
177
+ onTransformChange?.({ zoom: newZoom, pan });
178
+ }) as Handler<"wheel">,
179
+ },
180
+ {
181
+ drag: {
182
+ enabled,
183
+ filterTaps: true,
184
+ },
185
+ pinch: {
186
+ enabled,
187
+ scaleBounds: { min: minZoom, max: maxZoom },
188
+ from: () => [zoom, 0],
189
+ },
190
+ wheel: {
191
+ enabled,
192
+ eventOptions: { passive: false },
193
+ },
194
+ },
195
+ );
196
+
197
+ // Reset to initial values
198
+ const resetTransform = useCallback(() => {
199
+ updateTransform(initialZoom, initialPan);
200
+ }, [initialZoom, initialPan, updateTransform]);
201
+
202
+ useEffect(() => {
203
+ updateTransform(initialZoom, initialPan);
204
+ }, [initialZoom, initialPan.x, initialPan.y, updateTransform]);
205
+
206
+ // Programmatic setters
207
+ const setZoom = useCallback(
208
+ (newZoom: number) => {
209
+ updateTransform(clampZoom(newZoom), pan);
210
+ },
211
+ [pan, clampZoom, updateTransform],
212
+ );
213
+
214
+ const setPan = useCallback(
215
+ (newPan: { x: number; y: number }) => {
216
+ updateTransform(zoom, newPan);
217
+ },
218
+ [zoom, updateTransform],
219
+ );
220
+
221
+ // CSS transform style for HTML mode
222
+ const style = useMemo<React.CSSProperties>(
223
+ () =>
224
+ mode === "css"
225
+ ? {
226
+ transform: `translate(${pan.x}px, ${pan.y}px) scale(${zoom})`,
227
+ transformOrigin: "center center",
228
+ }
229
+ : {},
230
+ [mode, pan.x, pan.y, zoom],
231
+ );
232
+
233
+ // Current transform state
234
+ const transform = useMemo<PanZoomTransform>(
235
+ () => ({ zoom, pan }),
236
+ [zoom, pan],
237
+ );
238
+
239
+ // Wrap bind to ensure it always returns spreadable props (never void)
240
+ // We exclude 'ref' from the result to avoid type conflicts with explicit element refs
241
+ const safeBind: GestureBindFunction = useCallback(() => {
242
+ const result = bind();
243
+ // If bind returns void (shouldn't happen with our config), return empty object
244
+ // Destructure to omit ref, avoiding type conflicts with SVG/HTML element refs
245
+
246
+ const { ref: _ref, ...propsWithoutRef } = (result ??
247
+ {}) as React.HTMLAttributes<Element> & { ref?: unknown };
248
+ return propsWithoutRef;
249
+ }, [bind]);
250
+
251
+ return {
252
+ transform,
253
+ bind: safeBind,
254
+ resetTransform,
255
+ setZoom,
256
+ setPan,
257
+ style,
258
+ isDragging,
259
+ isPinching,
260
+ };
261
+ }
262
+
263
+ /**
264
+ * Helper to calculate SVG viewBox with pan/zoom applied
265
+ */
266
+ export function calculateViewBox(
267
+ bounds: { minX: number; minY: number; width: number; height: number },
268
+ transform: PanZoomTransform,
269
+ ): string {
270
+ const viewBoxWidth = bounds.width / transform.zoom;
271
+ const viewBoxHeight = bounds.height / transform.zoom;
272
+ const viewBoxX =
273
+ bounds.minX + (bounds.width - viewBoxWidth) / 2 - transform.pan.x;
274
+ const viewBoxY =
275
+ bounds.minY + (bounds.height - viewBoxHeight) / 2 - transform.pan.y;
276
+
277
+ return `${viewBoxX} ${viewBoxY} ${viewBoxWidth} ${viewBoxHeight}`;
278
+ }
@@ -0,0 +1,28 @@
1
+ import { useMemo } from "react";
2
+ import type { PlayerId } from "@dreamboard/manifest-contract";
3
+ import { useLobbyState } from "./useLobby.js";
4
+ import type { Player } from "./useMe.js";
5
+
6
+ export function usePlayerInfo(): Map<PlayerId, Player> {
7
+ const lobby = useLobbyState();
8
+
9
+ return useMemo(() => {
10
+ if (!lobby) {
11
+ return new Map();
12
+ }
13
+
14
+ const playerMap = new Map<PlayerId, Player>();
15
+
16
+ for (const seat of lobby.seats) {
17
+ const playerId = seat.playerId as PlayerId;
18
+ playerMap.set(playerId, {
19
+ playerId,
20
+ name: seat.displayName,
21
+ isHost: seat.isHost,
22
+ color: seat.playerColor,
23
+ });
24
+ }
25
+
26
+ return playerMap;
27
+ }, [lobby]);
28
+ }
@@ -0,0 +1,23 @@
1
+ import { useMemo } from "react";
2
+ import type { PlayerId } from "@dreamboard/manifest-contract";
3
+ import { useLobby } from "./useLobby.js";
4
+
5
+ /**
6
+ * Returns the player ids in turn order, as provided by the lobby seat
7
+ * assignments. Matches `q.player.order()` on the reducer side: the
8
+ * engine's turn order is seeded from the same seat assignments.
9
+ *
10
+ * - Returns an empty array before the first lobby snapshot arrives.
11
+ * - Stable reference across renders when the seats don't change.
12
+ *
13
+ * Prefer this hook (combined with `useActivePlayers()` for the current
14
+ * seat) over re-projecting `turnOrder` into the view — flow state
15
+ * belongs to the engine and the SDK, not to game-specific projections.
16
+ */
17
+ export function usePlayerTurnOrder(): readonly PlayerId[] {
18
+ const lobby = useLobby();
19
+ return useMemo(() => {
20
+ if (!lobby) return [];
21
+ return lobby.seats.map((seat) => seat.playerId as PlayerId);
22
+ }, [lobby]);
23
+ }
@@ -0,0 +1,102 @@
1
+ import { afterEach, expect, mock, test } from "bun:test";
2
+ import { renderToString } from "react-dom/server";
3
+ import type { PluginStateSnapshot } from "../types/plugin-state.js";
4
+ import type { PluginSessionState } from "../types/runtime-api.js";
5
+
6
+ const actualCreatePluginRuntimeModule = await import(
7
+ "../runtime/createPluginRuntimeAPI.js"
8
+ );
9
+
10
+ type RuntimeModule = typeof actualCreatePluginRuntimeModule;
11
+
12
+ const createPluginRuntimeApiMock = mock();
13
+
14
+ mock.module("../runtime/createPluginRuntimeAPI.js", () => ({
15
+ ...(actualCreatePluginRuntimeModule as RuntimeModule),
16
+ createPluginRuntimeAPI: createPluginRuntimeApiMock,
17
+ }));
18
+
19
+ function createSessionState(): PluginSessionState {
20
+ return {
21
+ status: "ready",
22
+ sessionId: "session-1",
23
+ controllablePlayerIds: ["player-1"],
24
+ controllingPlayerId: "player-1",
25
+ userId: "user-1",
26
+ };
27
+ }
28
+
29
+ function createSnapshot(
30
+ view: PluginStateSnapshot["view"],
31
+ ): PluginStateSnapshot {
32
+ return {
33
+ view,
34
+ gameplay: {
35
+ currentPhase: "setup",
36
+ currentStage: null,
37
+ activePlayers: ["player-1"],
38
+ availableInteractions: [],
39
+ zones: {},
40
+ },
41
+ lobby: null,
42
+ notifications: [],
43
+ session: createSessionState(),
44
+ history: null,
45
+ syncId: 1,
46
+ };
47
+ }
48
+
49
+ function createRuntime(snapshot: PluginStateSnapshot) {
50
+ return {
51
+ validateInteraction: async () => ({ valid: true }),
52
+ submitInteraction: async () => undefined,
53
+ getSessionState: () => snapshot.session,
54
+ disconnect: () => undefined,
55
+ getSnapshot: () => snapshot,
56
+ subscribeToState: () => () => undefined,
57
+ };
58
+ }
59
+
60
+ async function loadUsePluginRuntime() {
61
+ return import(`./usePluginRuntime.ts?test=${Math.random()}`);
62
+ }
63
+
64
+ afterEach(() => {
65
+ createPluginRuntimeApiMock.mockReset();
66
+ });
67
+
68
+ test("usePluginRuntime stays unready when the initial snapshot has no projected view", async () => {
69
+ createPluginRuntimeApiMock.mockReturnValue(
70
+ createRuntime(createSnapshot(null)),
71
+ );
72
+ const { usePluginRuntime } = await loadUsePluginRuntime();
73
+ let captured: ReturnType<typeof usePluginRuntime> | null = null;
74
+
75
+ function Harness() {
76
+ captured = usePluginRuntime();
77
+ return null;
78
+ }
79
+
80
+ renderToString(<Harness />);
81
+
82
+ expect(captured?.isReady).toBe(false);
83
+ expect(captured?.error).toBeNull();
84
+ });
85
+
86
+ test("usePluginRuntime is ready when the initial snapshot already has a projected view", async () => {
87
+ createPluginRuntimeApiMock.mockReturnValue(
88
+ createRuntime(createSnapshot({ board: "ready" })),
89
+ );
90
+ const { usePluginRuntime } = await loadUsePluginRuntime();
91
+ let captured: ReturnType<typeof usePluginRuntime> | null = null;
92
+
93
+ function Harness() {
94
+ captured = usePluginRuntime();
95
+ return null;
96
+ }
97
+
98
+ renderToString(<Harness />);
99
+
100
+ expect(captured?.isReady).toBe(true);
101
+ expect(captured?.error).toBeNull();
102
+ });
@@ -0,0 +1,130 @@
1
+ import { useState, useEffect } from "react";
2
+ import {
3
+ createPluginRuntimeAPI,
4
+ type PluginRuntimeAPI,
5
+ } from "../runtime/createPluginRuntimeAPI.js";
6
+
7
+ export interface UsePluginRuntimeOptions {
8
+ /**
9
+ * Timeout in milliseconds to wait for state-sync.
10
+ * @default 10000 (10 seconds)
11
+ */
12
+ timeout?: number;
13
+ }
14
+
15
+ export interface UsePluginRuntimeResult {
16
+ /** The RuntimeAPI instance */
17
+ runtime: PluginRuntimeAPI;
18
+ /** Whether the initial reducer-native snapshot is available and ready */
19
+ isReady: boolean;
20
+ /** Error message if initialization failed */
21
+ error: string | null;
22
+ }
23
+
24
+ function hasProjectedView(
25
+ snapshot: ReturnType<PluginRuntimeAPI["getSnapshot"]> | null | undefined,
26
+ ): boolean {
27
+ return (
28
+ snapshot !== null &&
29
+ snapshot !== undefined &&
30
+ snapshot.view !== null &&
31
+ snapshot.view !== undefined
32
+ );
33
+ }
34
+
35
+ /**
36
+ * Hook that creates and manages a PluginRuntimeAPI instance.
37
+ *
38
+ * This hook handles:
39
+ * 1. Creating the RuntimeAPI
40
+ * 2. Waiting for the first state-sync snapshot before setting isReady
41
+ *
42
+ * In the new architecture, the host only renders the plugin when a reducer-native
43
+ * snapshot is available, so isReady should become true quickly after init.
44
+ *
45
+ * @example
46
+ * ```tsx
47
+ * function PluginRuntime({ children }: { children: React.ReactNode }) {
48
+ * const { runtime, isReady, error } = usePluginRuntime();
49
+ *
50
+ * if (error) {
51
+ * return <div>Error: {error}</div>;
52
+ * }
53
+ *
54
+ * if (!isReady) {
55
+ * return <GameSkeleton message="Waiting for game state..." />;
56
+ * }
57
+ *
58
+ * return <RuntimeProvider runtime={runtime}>{children}</RuntimeProvider>;
59
+ * }
60
+ * ```
61
+ */
62
+ export function usePluginRuntime(
63
+ options: UsePluginRuntimeOptions = {},
64
+ ): UsePluginRuntimeResult {
65
+ const { timeout = 10000 } = options;
66
+
67
+ // Create runtime once and keep stable reference
68
+ const [runtime] = useState<PluginRuntimeAPI>(() => createPluginRuntimeAPI());
69
+ const [isReady, setIsReady] = useState(() => {
70
+ const snapshot = runtime.getSnapshot?.();
71
+ return hasProjectedView(snapshot);
72
+ });
73
+ const [error, setError] = useState<string | null>(null);
74
+
75
+ // Subscribe to state-sync and set isReady when the first snapshot arrives.
76
+ useEffect(() => {
77
+ const markReadyFromSnapshot = () => {
78
+ const currentSnapshot = runtime.getSnapshot?.();
79
+ if (!hasProjectedView(currentSnapshot)) {
80
+ return false;
81
+ }
82
+ setError(null);
83
+ setIsReady(true);
84
+ return true;
85
+ };
86
+
87
+ if (markReadyFromSnapshot()) {
88
+ return;
89
+ }
90
+
91
+ // Set up timeout
92
+ const timeoutId = setTimeout(() => {
93
+ if (!markReadyFromSnapshot()) {
94
+ setError(
95
+ `Timed out waiting for the initial projected view after ${timeout}ms. ` +
96
+ "Ensure the host sends a reducer-native state-sync with a seat view.",
97
+ );
98
+ }
99
+ }, timeout);
100
+
101
+ // Fallback poll for dev/HMR flows where the runtime snapshot may already
102
+ // exist but the first subscribe callback is missed.
103
+ const pollId = setInterval(() => {
104
+ if (markReadyFromSnapshot()) {
105
+ clearInterval(pollId);
106
+ clearTimeout(timeoutId);
107
+ }
108
+ }, 100);
109
+
110
+ // Subscribe to state changes
111
+ const unsubscribe = runtime.subscribeToState?.((state) => {
112
+ if (!hasProjectedView(state)) {
113
+ setIsReady(false);
114
+ return;
115
+ }
116
+ clearInterval(pollId);
117
+ clearTimeout(timeoutId);
118
+ setError(null);
119
+ setIsReady(true);
120
+ });
121
+
122
+ return () => {
123
+ clearInterval(pollId);
124
+ clearTimeout(timeoutId);
125
+ unsubscribe?.();
126
+ };
127
+ }, [runtime, timeout]);
128
+
129
+ return { runtime, isReady, error };
130
+ }
@@ -0,0 +1,61 @@
1
+ import { usePluginState } from "../context/PluginStateContext.js";
2
+ import type { InteractionDescriptor } from "../types/plugin-state.js";
3
+ import {
4
+ eligibleTargetsByBoardKind,
5
+ hasBoardTargetInput,
6
+ } from "../utils/interaction-inputs.js";
7
+
8
+ /**
9
+ * Structured inbox view of the controlling seat's available interactions.
10
+ * Interactions are grouped into UI behavior buckets. Prompt-kind interactions
11
+ * (authored via `promptInput(...)`) surface at `bySurface.inbox`.
12
+ */
13
+ export interface SeatInbox {
14
+ /** Interactions grouped by derived UI bucket id. */
15
+ bySurface: Record<string, readonly InteractionDescriptor[]>;
16
+ /** Prompt-kind interactions addressed to the controlling seat. */
17
+ prompts: readonly InteractionDescriptor[];
18
+ /** Flat list of all available interactions (ungrouped). */
19
+ all: readonly InteractionDescriptor[];
20
+ }
21
+
22
+ /**
23
+ * Returns the controlling seat's available interactions grouped by UI bucket.
24
+ * Prompt-kind interactions (authored via `promptInput(...)`) appear both in
25
+ * `bySurface.inbox` and in `prompts`. Backed by authoritative descriptors
26
+ * from the trusted bundle — clients MUST NOT recompute availability.
27
+ */
28
+ export function useSeatInbox(): SeatInbox {
29
+ const interactions = usePluginState(
30
+ (s) => s.gameplay.availableInteractions ?? [],
31
+ );
32
+
33
+ const bySurface: Record<string, InteractionDescriptor[]> = {};
34
+ const prompts: InteractionDescriptor[] = [];
35
+ for (const descriptor of interactions) {
36
+ const surface = bucketForDescriptor(descriptor);
37
+ (bySurface[surface] ??= []).push(descriptor);
38
+ if (descriptor.kind === "prompt") {
39
+ prompts.push(descriptor);
40
+ }
41
+ }
42
+
43
+ return {
44
+ bySurface,
45
+ prompts,
46
+ all: interactions,
47
+ };
48
+ }
49
+
50
+ function bucketForDescriptor(descriptor: InteractionDescriptor): string {
51
+ if (descriptor.kind === "prompt") return "inbox";
52
+ if (descriptor.zoneId) return "hand";
53
+ if (hasBoardTargetInput(descriptor)) {
54
+ const byKind = eligibleTargetsByBoardKind(descriptor);
55
+ if (byKind.vertex) return "board-vertex";
56
+ if (byKind.edge) return "board-edge";
57
+ if (byKind.tile) return "board-tile";
58
+ if (byKind.space) return "board-space";
59
+ }
60
+ return "panel";
61
+ }
@@ -0,0 +1,10 @@
1
+ import { usePluginState } from "../context/PluginStateContext.js";
2
+ import type { SimultaneousPhaseSnapshot } from "../types/plugin-state.js";
3
+
4
+ /**
5
+ * Returns visibility-safe progress metadata for the active simultaneous-player
6
+ * phase, or null when no simultaneous submission barrier is active.
7
+ */
8
+ export function useSimultaneousPhase(): SimultaneousPhaseSnapshot | null {
9
+ return usePluginState((state) => state.gameplay.simultaneousPhase ?? null);
10
+ }