@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,219 @@
1
+ import { useState, type CSSProperties, type ReactNode } from "react";
2
+ import type { ButtonVariant } from "../../../theme/derive.js";
3
+ import { useTheme } from "../../../theme/ThemeProvider.js";
4
+ import type {
5
+ InteractionHandle,
6
+ InteractionParamsShape,
7
+ } from "../../../hooks/useInteractionHandle.js";
8
+ import type { InteractionDescriptor } from "../../../types/plugin-state.js";
9
+ import {
10
+ InteractionForm,
11
+ hasDefaultInteractionFormFields,
12
+ } from "../../InteractionForm.js";
13
+ import { interactionLabel } from "../../../utils/interaction-labels.js";
14
+ import { ThemedButton } from "../../ThemedButton.js";
15
+
16
+ export interface SubmittedActionConfig {
17
+ label?: ReactNode;
18
+ icon?: ReactNode;
19
+ variant?: ButtonVariant;
20
+ }
21
+
22
+ /**
23
+ * Default button used by every surface that does not get an explicit
24
+ * renderer override. The button reads its visual style from the active
25
+ * {@link useTheme()} via {@link buttonStyle}; styling is no longer
26
+ * configurable per call site. Authors who need a different look should
27
+ * either:
28
+ *
29
+ * 1. Mount a different theme via `<ThemeProvider>`, or
30
+ * 2. Provide a per-interaction renderer override on the surrounding
31
+ * surface and draw their own button.
32
+ *
33
+ * The mapping from `descriptor.emphasis` to a {@link ButtonVariant}:
34
+ *
35
+ * - `"primary"` → `primary`
36
+ * - `"destructive"` → `danger`
37
+ * - `"secondary"` (or unset) → `secondary`
38
+ *
39
+ * Override the mapping per call site with the `variant` prop when the
40
+ * descriptor's emphasis hint is wrong (e.g. an unavailable confirm that
41
+ * should still look prominent).
42
+ */
43
+ export interface DefaultInteractionButtonProps<
44
+ Params extends InteractionParamsShape = InteractionParamsShape,
45
+ > {
46
+ descriptor: InteractionDescriptor;
47
+ handle: InteractionHandle<Params>;
48
+ /** Override the variant inferred from `descriptor.emphasis`. */
49
+ variant?: ButtonVariant;
50
+ /** Content slot before the descriptor's icon and label. */
51
+ leading?: ReactNode;
52
+ /** Content slot after the descriptor's label. */
53
+ trailing?: ReactNode;
54
+ /**
55
+ * Prefer `descriptor.shortLabel` over `label`. Set by surfaces that
56
+ * group lots of interactions in a tight row.
57
+ */
58
+ compact?: boolean;
59
+ /**
60
+ * Button size token. Defaults to `md` (or `sm` when {@link compact}
61
+ * is set, preserving the historical sub-row geometry). Surfaces that
62
+ * resolve a salience tier — e.g. {@link PanelSurface} — pass
63
+ * `lg` for hero items so the visual weight matches the importance.
64
+ */
65
+ size?: "sm" | "md" | "lg";
66
+ /** Submit params forwarded to `handle.submit`. Defaults to `{}`. */
67
+ params?: Record<string, unknown>;
68
+ /** Copy and visual overrides once this interaction has been submitted. */
69
+ whenSubmitted?: SubmittedActionConfig;
70
+ /** Additional inline style merged after the resolved button style. */
71
+ style?: CSSProperties;
72
+ /** Start expanded when the descriptor needs form input. */
73
+ defaultFormOpen?: boolean;
74
+ /**
75
+ * Additional `data-*` attribute forwarded onto the `<button>` so
76
+ * surfaces can tag DOM nodes for tests / theming hooks (e.g.
77
+ * `data-panel-tier="hero"`).
78
+ */
79
+ "data-panel-tier"?: string;
80
+ }
81
+
82
+ /**
83
+ * @see DefaultInteractionButtonProps
84
+ */
85
+ export function DefaultInteractionButton<
86
+ Params extends InteractionParamsShape = InteractionParamsShape,
87
+ >({
88
+ descriptor,
89
+ handle,
90
+ variant: variantOverride,
91
+ leading,
92
+ trailing,
93
+ compact,
94
+ size,
95
+ params,
96
+ whenSubmitted,
97
+ style,
98
+ defaultFormOpen = false,
99
+ "data-panel-tier": panelTier,
100
+ }: DefaultInteractionButtonProps<Params>) {
101
+ const theme = useTheme();
102
+ const [pending, setPending] = useState(false);
103
+ const [formOpen, setFormOpen] = useState(defaultFormOpen);
104
+ const submitted = handle.status === "submitted";
105
+ const fallbackLabel = interactionLabel(descriptor);
106
+ const variant: ButtonVariant = submitted
107
+ ? (whenSubmitted?.variant ?? "submitted")
108
+ : (variantOverride ?? "secondary");
109
+ const disabled =
110
+ submitted ||
111
+ !descriptor.available ||
112
+ pending ||
113
+ handle.status === "submitting";
114
+ const needsForm = hasDefaultInteractionFormFields(descriptor);
115
+ const label = submitted
116
+ ? (whenSubmitted?.label ?? fallbackLabel)
117
+ : fallbackLabel;
118
+ const tooltip = descriptor.available
119
+ ? undefined
120
+ : formatUnavailableReason(descriptor.unavailableReason);
121
+
122
+ // Resolve size with the historical default — `compact` keeps `sm`
123
+ // for grouped sub-rows so existing call sites that rely on the
124
+ // tighter geometry don't change. Otherwise honour the explicit
125
+ // `size` prop, falling back to `md`.
126
+ const resolvedSize: "sm" | "md" | "lg" = size ?? (compact ? "sm" : "md");
127
+
128
+ const button = (
129
+ <ThemedButton
130
+ type="button"
131
+ variant={variant}
132
+ size={resolvedSize}
133
+ pressed={pending || handle.status === "submitting"}
134
+ aria-label={typeof label === "string" ? label : fallbackLabel}
135
+ aria-expanded={needsForm ? formOpen : undefined}
136
+ aria-disabled={disabled || undefined}
137
+ data-interaction-id={descriptor.interactionId}
138
+ data-emphasis="secondary"
139
+ data-panel-tier={panelTier}
140
+ data-available={descriptor.available && !submitted ? "true" : "false"}
141
+ data-action-state={
142
+ submitted
143
+ ? "submitted"
144
+ : handle.status === "submitting"
145
+ ? "submitting"
146
+ : descriptor.available
147
+ ? "available"
148
+ : "unavailable"
149
+ }
150
+ title={tooltip}
151
+ disabled={disabled}
152
+ style={style}
153
+ onClick={async (event) => {
154
+ event.preventDefault();
155
+ if (disabled) return;
156
+ if (needsForm) {
157
+ setFormOpen((open) => !open);
158
+ return;
159
+ }
160
+ setPending(true);
161
+ try {
162
+ if (params !== undefined) {
163
+ await handle.submit(params as Params);
164
+ } else {
165
+ await handle.submitDraft();
166
+ }
167
+ } catch {
168
+ // Descriptor-level availability is authoritative; submission
169
+ // errors flow through the runtime's error channel. We swallow
170
+ // here so consumers without an error boundary don't see an
171
+ // unhandled rejection warning.
172
+ } finally {
173
+ setPending(false);
174
+ }
175
+ }}
176
+ >
177
+ {leading}
178
+ {submitted && whenSubmitted?.icon ? (
179
+ <span aria-hidden style={{ fontSize: "1.1em" }}>
180
+ {whenSubmitted.icon}
181
+ </span>
182
+ ) : null}
183
+ <span>{label}</span>
184
+ {trailing}
185
+ </ThemedButton>
186
+ );
187
+
188
+ if (!needsForm) return button;
189
+ return (
190
+ <span
191
+ data-default-interaction
192
+ style={{
193
+ display: "inline-flex",
194
+ flexDirection: "column",
195
+ alignItems: "stretch",
196
+ gap: theme.space[2],
197
+ }}
198
+ >
199
+ {button}
200
+ {formOpen ? (
201
+ <InteractionForm
202
+ descriptor={descriptor}
203
+ handle={handle}
204
+ onCancel={() => setFormOpen(false)}
205
+ onSubmitSuccess={() => setFormOpen(false)}
206
+ />
207
+ ) : null}
208
+ </span>
209
+ );
210
+ }
211
+
212
+ function formatUnavailableReason(
213
+ reason: string | undefined,
214
+ ): string | undefined {
215
+ if (reason === "INSUFFICIENT_RESOURCES") {
216
+ return "Insufficient resources";
217
+ }
218
+ return reason;
219
+ }
@@ -0,0 +1,311 @@
1
+ import { useCallback, useMemo, useState } from "react";
2
+ import { useStore } from "zustand";
3
+ import { useInteractionUiStore } from "../../../context/InteractionDraftContext.js";
4
+ import { usePluginSession } from "../../../context/PluginSessionContext.js";
5
+ import { usePluginState } from "../../../context/PluginStateContext.js";
6
+ import { useRuntimeContext } from "../../../context/RuntimeContext.js";
7
+ import type {
8
+ InteractionDescriptor,
9
+ ZoneHandlesSnapshot,
10
+ } from "../../../types/plugin-state.js";
11
+ import {
12
+ hasInteractionFieldErrors,
13
+ inputByTarget,
14
+ interactionArmScope,
15
+ interactionInputKeys,
16
+ isInputValueReady,
17
+ toggleManyValue,
18
+ validateInteractionInputDomains,
19
+ } from "../../../utils/interaction-inputs.js";
20
+ import type {
21
+ InteractionActionState,
22
+ InteractionDisabledReason,
23
+ } from "../../../utils/interaction-status.js";
24
+ import type { ViewCard } from "@dreamboard/sdk-types";
25
+
26
+ export interface CardZoneInteractionContext<I extends string = string> {
27
+ card: ViewCard;
28
+ interactions: ReadonlyArray<InteractionDescriptor<I>>;
29
+ play: ((params?: Record<string, unknown>) => Promise<void>) | null;
30
+ disabled: boolean;
31
+ disabledReason?: InteractionDisabledReason;
32
+ actionState: InteractionActionState;
33
+ selected: boolean;
34
+ }
35
+
36
+ export function useCardZoneInteractions<I extends string = string>(
37
+ zoneId: string,
38
+ _options: { surface: "hand" | "market" },
39
+ ) {
40
+ const runtime = useRuntimeContext();
41
+ const { controllingPlayerId } = usePluginSession();
42
+ const draftStore = useInteractionUiStore();
43
+ const draftSnapshot = useStore(draftStore, (state) => state.drafts);
44
+ const submittingSnapshot = useStore(draftStore, (state) => state.submitting);
45
+ const [followUp, setFollowUp] = useState<InteractionDescriptor<I> | null>(
46
+ null,
47
+ );
48
+ const zone = usePluginState((s) => s.gameplay.zones?.[zoneId]) as
49
+ | ZoneHandlesSnapshot<I>
50
+ | undefined;
51
+ const simultaneousPhase = usePluginState((s) => s.gameplay.simultaneousPhase);
52
+
53
+ const cards = useMemo<readonly ViewCard[]>(() => {
54
+ if (!zone) return [];
55
+ const list: ViewCard[] = [];
56
+ for (const cardId of zone.cardIds) {
57
+ const serialized = zone.cardsById[cardId];
58
+ if (!serialized) continue;
59
+ try {
60
+ list.push(JSON.parse(serialized) as ViewCard);
61
+ } catch {
62
+ // Skip malformed card snapshots defensively.
63
+ }
64
+ }
65
+ return list;
66
+ }, [zone]);
67
+
68
+ const submitInteractionDraft = useCallback(
69
+ async (
70
+ descriptor: InteractionDescriptor<I>,
71
+ params: Record<string, unknown>,
72
+ ) => {
73
+ if (!controllingPlayerId) return;
74
+ if (draftStore.isSubmitting(descriptor.interactionKey)) return;
75
+ draftStore.setSubmitting(descriptor.interactionKey, true);
76
+ try {
77
+ await runtime.submitInteraction(
78
+ controllingPlayerId,
79
+ descriptor.interactionId,
80
+ params,
81
+ );
82
+ draftStore.clearInput(descriptor.interactionKey);
83
+ const armScope = interactionArmScope(descriptor);
84
+ if (draftStore.getArmed(armScope) === descriptor.interactionKey) {
85
+ draftStore.arm(armScope, null);
86
+ }
87
+ } finally {
88
+ draftStore.setSubmitting(descriptor.interactionKey, false);
89
+ }
90
+ },
91
+ [controllingPlayerId, draftStore, runtime],
92
+ );
93
+
94
+ const playCardInteraction = useCallback(
95
+ async (
96
+ card: ViewCard,
97
+ descriptor: InteractionDescriptor<I>,
98
+ params?: Record<string, unknown>,
99
+ ) => {
100
+ if (!controllingPlayerId) return;
101
+ const cardInput = resolveCardInput(descriptor, card.id);
102
+ if (!cardInput) return;
103
+ const cardInputKey = cardInput.key;
104
+ const currentDraft = draftStore.getDraft(descriptor.interactionKey);
105
+ const nextCardValue =
106
+ cardInput.domain.type === "target" &&
107
+ cardInput.domain.selection?.mode === "many"
108
+ ? toggleManyValue(
109
+ currentDraft[cardInputKey],
110
+ card.id,
111
+ cardInput.domain.selection,
112
+ )
113
+ : card.id;
114
+ const nextDraft: Record<string, unknown> = {
115
+ ...currentDraft,
116
+ ...(params ?? {}),
117
+ [cardInputKey]: nextCardValue,
118
+ };
119
+ for (const [key, value] of Object.entries(params ?? {})) {
120
+ draftStore.setInput(descriptor.interactionKey, key, value);
121
+ }
122
+ draftStore.setInput(
123
+ descriptor.interactionKey,
124
+ cardInputKey,
125
+ nextCardValue,
126
+ );
127
+ if (
128
+ cardInput.domain.type === "target" &&
129
+ cardInput.domain.selection?.mode === "many"
130
+ ) {
131
+ if (
132
+ descriptor.commit.mode === "autoWhenReady" &&
133
+ isDraftReady(descriptor, nextDraft)
134
+ ) {
135
+ await submitInteractionDraft(descriptor, nextDraft);
136
+ }
137
+ return;
138
+ }
139
+ const remaining = descriptor.inputs.filter((input) => {
140
+ const value =
141
+ nextDraft[input.key] ??
142
+ ("defaultValue" in input ? input.defaultValue : undefined);
143
+ return input.key !== cardInputKey && value === undefined;
144
+ });
145
+ const needsBoardTarget = descriptor.inputs.some((input) => {
146
+ const value =
147
+ nextDraft[input.key] ??
148
+ ("defaultValue" in input ? input.defaultValue : undefined);
149
+ return (
150
+ input.key !== cardInputKey &&
151
+ input.domain.type === "target" &&
152
+ value === undefined
153
+ );
154
+ });
155
+ if (needsBoardTarget) {
156
+ setFollowUp(null);
157
+ draftStore.arm(
158
+ interactionArmScope(descriptor),
159
+ descriptor.interactionKey,
160
+ );
161
+ return;
162
+ }
163
+ if (remaining.length > 0) {
164
+ setFollowUp(descriptor);
165
+ return;
166
+ }
167
+ if (
168
+ !isDraftReady(descriptor, nextDraft) ||
169
+ descriptor.commit.mode !== "autoWhenReady"
170
+ ) {
171
+ setFollowUp(null);
172
+ draftStore.arm(
173
+ interactionArmScope(descriptor),
174
+ descriptor.interactionKey,
175
+ );
176
+ return;
177
+ }
178
+ await submitInteractionDraft(descriptor, nextDraft);
179
+ },
180
+ [controllingPlayerId, draftStore, submitInteractionDraft],
181
+ );
182
+
183
+ const contexts = useMemo<ReadonlyArray<CardZoneInteractionContext<I>>>(() => {
184
+ if (!zone) return [];
185
+ return cards.map((card) => {
186
+ const interactions = zone.playableByCardId[card.id] ?? [];
187
+ const submittedInteraction = interactions.find(
188
+ (d) =>
189
+ controllingPlayerId !== null &&
190
+ simultaneousPhase?.phaseName === d.phaseName &&
191
+ simultaneousPhase.interactionId === d.interactionId &&
192
+ simultaneousPhase.sealedPlayerIds.includes(controllingPlayerId),
193
+ );
194
+ const submittingInteraction = interactions.find((d) =>
195
+ draftStore.isSubmitting(d.interactionKey),
196
+ );
197
+ const selected = interactions.some((d) =>
198
+ isCardSelected(d, card.id, draftStore.getDraft(d.interactionKey)),
199
+ );
200
+ const blockedState: InteractionActionState | null = submittedInteraction
201
+ ? "submitted"
202
+ : submittingInteraction
203
+ ? "submitting"
204
+ : null;
205
+ const available = blockedState
206
+ ? []
207
+ : interactions.filter(
208
+ (d) =>
209
+ d.available !== false &&
210
+ isCardInteractionSelectable(
211
+ d,
212
+ card.id,
213
+ draftStore.getDraft(d.interactionKey),
214
+ ),
215
+ );
216
+ const first = available.length === 1 ? available[0] : undefined;
217
+ const limited =
218
+ !blockedState &&
219
+ interactions.some(
220
+ (d) =>
221
+ d.available !== false &&
222
+ !isCardInteractionSelectable(
223
+ d,
224
+ card.id,
225
+ draftStore.getDraft(d.interactionKey),
226
+ ),
227
+ );
228
+ const disabled = blockedState !== null || available.length === 0;
229
+ return {
230
+ card,
231
+ interactions,
232
+ play: first
233
+ ? (params?: Record<string, unknown>) =>
234
+ playCardInteraction(card, first, params)
235
+ : null,
236
+ disabled,
237
+ disabledReason:
238
+ blockedState ??
239
+ (limited ? "selection-limit" : disabled ? "unavailable" : undefined),
240
+ actionState: blockedState ?? (disabled ? "unavailable" : "available"),
241
+ selected,
242
+ };
243
+ });
244
+ }, [
245
+ cards,
246
+ controllingPlayerId,
247
+ draftSnapshot,
248
+ draftStore,
249
+ playCardInteraction,
250
+ simultaneousPhase,
251
+ submittingSnapshot,
252
+ zone,
253
+ ]);
254
+
255
+ return { cards, contexts, followUp, setFollowUp };
256
+ }
257
+
258
+ function isCardSelected(
259
+ descriptor: InteractionDescriptor,
260
+ cardId: string,
261
+ draft: Readonly<Record<string, unknown>>,
262
+ ): boolean {
263
+ const input = resolveCardInput(descriptor, cardId);
264
+ if (!input) return false;
265
+ const current = draft[input.key];
266
+ return Array.isArray(current)
267
+ ? current.map((item) => String(item)).includes(cardId)
268
+ : String(current) === cardId;
269
+ }
270
+
271
+ function isCardInteractionSelectable(
272
+ descriptor: InteractionDescriptor,
273
+ cardId: string,
274
+ draft: Readonly<Record<string, unknown>>,
275
+ ): boolean {
276
+ const input = resolveCardInput(descriptor, cardId);
277
+ if (!input || input.domain.type !== "target") return true;
278
+ const selection = input.domain.selection;
279
+ if (selection?.mode !== "many" || !selection.distinct) return true;
280
+ const current = draft[input.key];
281
+ if (!Array.isArray(current)) return true;
282
+ if (current.map((item) => String(item)).includes(cardId)) return true;
283
+ return selection.max === undefined || current.length < selection.max;
284
+ }
285
+
286
+ function isDraftReady(
287
+ descriptor: InteractionDescriptor,
288
+ draft: Readonly<Record<string, unknown>>,
289
+ ): boolean {
290
+ const fieldErrors = validateInteractionInputDomains(descriptor, draft);
291
+ if (hasInteractionFieldErrors(fieldErrors)) return false;
292
+ return interactionInputKeys(descriptor).every((key) => {
293
+ const input = descriptor.inputs.find((candidate) => candidate.key === key);
294
+ const value =
295
+ draft[key] ??
296
+ (input && "defaultValue" in input ? input.defaultValue : undefined);
297
+ return input ? isInputValueReady(input, value) : value !== undefined;
298
+ });
299
+ }
300
+
301
+ function resolveCardInput(
302
+ descriptor: InteractionDescriptor,
303
+ cardId: string,
304
+ ): InteractionDescriptor["inputs"][number] | null {
305
+ const targetInput = inputByTarget(descriptor, "card", cardId);
306
+ if (targetInput) return targetInput;
307
+ if (interactionInputKeys(descriptor).includes("cardId")) {
308
+ return descriptor.inputs.find((input) => input.key === "cardId") ?? null;
309
+ }
310
+ return null;
311
+ }
@@ -0,0 +1,100 @@
1
+ import type { ReactNode } from "react";
2
+ import type {
3
+ InteractionHandle,
4
+ InteractionParamsShape,
5
+ } from "../../hooks/useInteractionHandle.js";
6
+ import type { InteractionDescriptor } from "../../types/plugin-state.js";
7
+ import type { SubmittedActionConfig } from "./internal/DefaultInteractionButton.js";
8
+
9
+ export type InteractionParamsByKeyShape = Record<
10
+ string,
11
+ | InteractionParamsShape
12
+ | {
13
+ params: InteractionParamsShape;
14
+ defaulted?: string;
15
+ }
16
+ >;
17
+
18
+ export type InteractionParamsOf<
19
+ ParamsByKey extends Partial<InteractionParamsByKeyShape>,
20
+ Key extends string,
21
+ > = Key extends keyof ParamsByKey
22
+ ? ParamsByKey[Key] extends {
23
+ params: infer Params extends InteractionParamsShape;
24
+ }
25
+ ? Params
26
+ : ParamsByKey[Key] extends InteractionParamsShape
27
+ ? ParamsByKey[Key]
28
+ : InteractionParamsShape
29
+ : InteractionParamsShape;
30
+
31
+ export type InteractionDefaultedKeysOf<
32
+ ParamsByKey extends Partial<InteractionParamsByKeyShape>,
33
+ Key extends string,
34
+ > = Key extends keyof ParamsByKey
35
+ ? ParamsByKey[Key] extends { defaulted?: infer Defaulted extends string }
36
+ ? Extract<Defaulted, keyof InteractionParamsOf<ParamsByKey, Key> & string>
37
+ : never
38
+ : never;
39
+
40
+ /**
41
+ * Per-interaction renderer overrides for a surface. Partial: when omitted
42
+ * entirely, the surface uses its built-in default renderer for every
43
+ * interaction. When present, every key MUST be a valid member of `I` —
44
+ * typos are a compile-time error against the generated `*Interactions`
45
+ * id alias from `@dreamboard/ui-contract`.
46
+ *
47
+ * ```ts
48
+ * import type { PanelInteractions } from "@dreamboard/ui-contract";
49
+ *
50
+ * <PanelSurface<PanelInteractions> render={{ rollDice: ... }} />
51
+ * // ✗ <PanelSurface<PanelInteractions> render={{ rolldice: ... }} />
52
+ * // ^^^^^^^^^ typo: not assignable
53
+ * ```
54
+ *
55
+ * If you want compile-time exhaustiveness (every interaction id in `I`
56
+ * must have an explicit renderer), use {@link ExhaustiveSurfaceRenderMap}
57
+ * instead.
58
+ */
59
+ export interface DefaultInteractionRenderConfig {
60
+ whenSubmitted?: SubmittedActionConfig;
61
+ }
62
+
63
+ export type SurfaceRenderEntry<D, H> =
64
+ | ((descriptor: D, handle: H) => ReactNode)
65
+ | DefaultInteractionRenderConfig;
66
+
67
+ export type SurfaceRenderMap<
68
+ I extends string,
69
+ ParamsByKey extends Partial<InteractionParamsByKeyShape> = {},
70
+ > = {
71
+ [K in I]?: SurfaceRenderEntry<
72
+ InteractionDescriptor<K>,
73
+ InteractionHandle<
74
+ InteractionParamsOf<ParamsByKey, K>,
75
+ InteractionDefaultedKeysOf<ParamsByKey, K>
76
+ >
77
+ >;
78
+ };
79
+
80
+ /**
81
+ * Exhaustive (required) variant of {@link SurfaceRenderMap}. Every key of
82
+ * `I` MUST have an explicit renderer — useful when authors want the
83
+ * compiler to enforce that no interaction id slips through without a
84
+ * deliberate visual treatment.
85
+ *
86
+ * ```ts
87
+ * import type { PanelInteractions } from "@dreamboard/ui-contract";
88
+ * import type { ExhaustiveSurfaceRenderMap } from "@dreamboard/ui-sdk";
89
+ *
90
+ * const panelRenderers: ExhaustiveSurfaceRenderMap<PanelInteractions> = {
91
+ * rollDice: ...,
92
+ * buildSettlement: ...,
93
+ * // omitting any id here is a compile-time error
94
+ * };
95
+ * ```
96
+ */
97
+ export type ExhaustiveSurfaceRenderMap<
98
+ I extends string,
99
+ ParamsByKey extends Partial<InteractionParamsByKeyShape> = {},
100
+ > = Required<SurfaceRenderMap<I, ParamsByKey>>;
@@ -0,0 +1,44 @@
1
+ import { createContext, useContext } from "react";
2
+
3
+ export interface ClientParamSchema {
4
+ safeParse: (value: unknown) =>
5
+ | { success: true; data: Record<string, unknown> }
6
+ | {
7
+ success: false;
8
+ error: {
9
+ issues: ReadonlyArray<{
10
+ path: readonly PropertyKey[];
11
+ message: string;
12
+ }>;
13
+ };
14
+ };
15
+ }
16
+
17
+ export type ClientParamSchemaMap = Readonly<
18
+ Record<string, Readonly<Record<string, ClientParamSchema>>>
19
+ >;
20
+
21
+ const ClientParamSchemaContext = createContext<ClientParamSchemaMap>({});
22
+
23
+ export function ClientParamSchemaProvider({
24
+ schemas,
25
+ children,
26
+ }: {
27
+ schemas?: ClientParamSchemaMap;
28
+ children: React.ReactNode;
29
+ }) {
30
+ return (
31
+ <ClientParamSchemaContext.Provider value={schemas ?? {}}>
32
+ {children}
33
+ </ClientParamSchemaContext.Provider>
34
+ );
35
+ }
36
+
37
+ export function useClientParamSchema(
38
+ phaseName: string | null | undefined,
39
+ interactionId: string,
40
+ ): ClientParamSchema | undefined {
41
+ const schemas = useContext(ClientParamSchemaContext);
42
+ if (!phaseName) return undefined;
43
+ return schemas[phaseName]?.[interactionId];
44
+ }