@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,168 @@
1
+ import type { ReactElement } from "react";
2
+ import {
3
+ PromptDialogHost as PromptDialogHostComponent,
4
+ type PromptDialogHostProps,
5
+ } from "./components/PromptDialogHost.js";
6
+ import {
7
+ Board as BoardPrimitive,
8
+ Interaction as InteractionPrimitive,
9
+ Phase as PhasePrimitive,
10
+ PlayerRoster as PlayerRosterPrimitive,
11
+ Prompt as PromptPrimitive,
12
+ PromptInbox as PromptInboxPrimitive,
13
+ Zone as ZonePrimitive,
14
+ type BoardTargetProps,
15
+ type InteractionCardInputProps,
16
+ type InteractionRootProps,
17
+ type PhaseSwitchProps,
18
+ type PlayerRosterComponents,
19
+ type PromptOptionProps,
20
+ type PromptRootProps,
21
+ type ZoneRootProps,
22
+ } from "./primitives/index.js";
23
+
24
+ /**
25
+ * Workspace-aware UI typing extension point.
26
+ *
27
+ * Generated workspaces will augment this interface with their concrete UI
28
+ * contract. The unregistered SDK keeps all public keys string-compatible so
29
+ * package-local tests and generic consumers can still import ui-sdk directly.
30
+ */
31
+ export interface DreamboardUIRegister {}
32
+
33
+ export type UIContractBucket = Record<string, unknown>;
34
+
35
+ export interface UIContract {
36
+ interactions?: UIContractBucket;
37
+ inputs?: UIContractBucket;
38
+ prompts?: UIContractBucket;
39
+ promptOptions?: UIContractBucket;
40
+ zones?: UIContractBucket;
41
+ cards?: UIContractBucket;
42
+ phases?: UIContractBucket;
43
+ boardTargets?: UIContractBucket;
44
+ }
45
+
46
+ type RegisteredUIContract = DreamboardUIRegister extends {
47
+ ui: infer Registered extends UIContract;
48
+ }
49
+ ? Registered
50
+ : UIContract;
51
+
52
+ type BucketOf<Contract extends UIContract, Key extends keyof UIContract> =
53
+ NonNullable<Contract[Key]> extends UIContractBucket
54
+ ? NonNullable<Contract[Key]>
55
+ : UIContractBucket;
56
+
57
+ type StringKeysOrFallback<Bucket extends UIContractBucket> =
58
+ string extends Extract<keyof Bucket, string>
59
+ ? string
60
+ : Extract<keyof Bucket, string>;
61
+
62
+ export type RegisteredUI = RegisteredUIContract;
63
+
64
+ export type InteractionKey<Contract extends UIContract = RegisteredUI> =
65
+ StringKeysOrFallback<BucketOf<Contract, "interactions">>;
66
+
67
+ export type InteractionInputKey<Contract extends UIContract = RegisteredUI> =
68
+ StringKeysOrFallback<BucketOf<Contract, "inputs">>;
69
+
70
+ export type PromptKey<Contract extends UIContract = RegisteredUI> =
71
+ StringKeysOrFallback<BucketOf<Contract, "prompts">>;
72
+
73
+ export type PromptOptionKey<Contract extends UIContract = RegisteredUI> =
74
+ StringKeysOrFallback<BucketOf<Contract, "promptOptions">>;
75
+
76
+ export type ZoneKey<Contract extends UIContract = RegisteredUI> =
77
+ StringKeysOrFallback<BucketOf<Contract, "zones">>;
78
+
79
+ export type CardKey<Contract extends UIContract = RegisteredUI> =
80
+ StringKeysOrFallback<BucketOf<Contract, "cards">>;
81
+
82
+ export type PhaseKey<Contract extends UIContract = RegisteredUI> =
83
+ StringKeysOrFallback<BucketOf<Contract, "phases">>;
84
+
85
+ export type BoardTargetKey<Contract extends UIContract = RegisteredUI> =
86
+ StringKeysOrFallback<BucketOf<Contract, "boardTargets">>;
87
+
88
+ export type TypedInteraction<Contract extends UIContract> = Omit<
89
+ typeof InteractionPrimitive,
90
+ "Root" | "CardInput"
91
+ > & {
92
+ Root<Interaction extends InteractionKey<Contract>>(
93
+ props: InteractionRootProps<Interaction>,
94
+ ): ReactElement | null;
95
+ CardInput<Input extends InteractionInputKey<Contract>>(
96
+ props: Omit<InteractionCardInputProps, "input"> & { input: Input },
97
+ ): ReactElement;
98
+ };
99
+
100
+ export type TypedPrompt<Contract extends UIContract> = Omit<
101
+ typeof PromptPrimitive,
102
+ "Root" | "Option"
103
+ > & {
104
+ Root<Prompt extends PromptKey<Contract>>(
105
+ props: PromptRootProps<Prompt>,
106
+ ): ReactElement | null;
107
+ Option<Option extends PromptOptionKey<Contract>>(
108
+ props: Omit<PromptOptionProps, "value"> & { value: Option },
109
+ ): ReactElement;
110
+ };
111
+
112
+ export type TypedPromptInbox = typeof PromptInboxPrimitive;
113
+ export type TypedPlayerRoster = PlayerRosterComponents;
114
+
115
+ export type TypedPhase<Contract extends UIContract> = Omit<
116
+ typeof PhasePrimitive,
117
+ "Switch"
118
+ > & {
119
+ Switch(props: PhaseSwitchProps<PhaseKey<Contract>>): ReactElement | null;
120
+ };
121
+
122
+ export type TypedZone<Contract extends UIContract> = Omit<
123
+ typeof ZonePrimitive,
124
+ "Root"
125
+ > & {
126
+ Root<Zone extends ZoneKey<Contract>>(
127
+ props: Omit<ZoneRootProps, "zone"> & { zone: Zone },
128
+ ): ReactElement;
129
+ };
130
+
131
+ export type TypedBoard<Contract extends UIContract> = Omit<
132
+ typeof BoardPrimitive,
133
+ "Target"
134
+ > & {
135
+ Target<Target extends BoardTargetKey<Contract>>(
136
+ props: Omit<BoardTargetProps, "value"> & { value: Target },
137
+ ): ReactElement;
138
+ };
139
+
140
+ export interface DreamboardUI<Contract extends UIContract = RegisteredUI> {
141
+ readonly contract: Contract;
142
+ readonly Interaction: TypedInteraction<Contract>;
143
+ readonly Prompt: TypedPrompt<Contract>;
144
+ readonly PromptInbox: TypedPromptInbox;
145
+ readonly PlayerRoster: TypedPlayerRoster;
146
+ readonly PromptDialogHost: (
147
+ props: PromptDialogHostProps,
148
+ ) => ReactElement | null;
149
+ readonly Phase: TypedPhase<Contract>;
150
+ readonly Zone: TypedZone<Contract>;
151
+ readonly Board: TypedBoard<Contract>;
152
+ }
153
+
154
+ export function createDreamboardUI<const Contract extends UIContract>(
155
+ contract: Contract,
156
+ ): DreamboardUI<Contract> {
157
+ return {
158
+ contract,
159
+ Interaction: InteractionPrimitive,
160
+ Prompt: PromptPrimitive,
161
+ PromptInbox: PromptInboxPrimitive,
162
+ PlayerRoster: PlayerRosterPrimitive,
163
+ PromptDialogHost: PromptDialogHostComponent,
164
+ Phase: PhasePrimitive,
165
+ Zone: ZonePrimitive,
166
+ Board: BoardPrimitive,
167
+ } as DreamboardUI<Contract>;
168
+ }
@@ -0,0 +1,109 @@
1
+ import { expect, test } from "bun:test";
2
+ import type { InteractionDescriptor } from "../types/plugin-state.js";
3
+ import {
4
+ hasInteractionFieldErrors,
5
+ validateInteractionInputDomains,
6
+ } from "./interaction-inputs.js";
7
+
8
+ function descriptor(
9
+ inputs: InteractionDescriptor["inputs"],
10
+ ): InteractionDescriptor {
11
+ return {
12
+ phaseName: "play",
13
+ interactionKey: "play.configure",
14
+ interactionId: "configure",
15
+ surface: "panel",
16
+ kind: "action",
17
+ label: "Configure",
18
+ inputs,
19
+ commit: { mode: "manual" },
20
+ available: true,
21
+ };
22
+ }
23
+
24
+ test("choiceList domains validate minimum and maximum selection counts", () => {
25
+ const interaction = descriptor([
26
+ {
27
+ key: "players",
28
+ kind: "form",
29
+ domain: {
30
+ type: "choiceList",
31
+ min: 2,
32
+ max: 3,
33
+ choices: [
34
+ { value: "p1", label: "Alice" },
35
+ { value: "p2", label: "Bob" },
36
+ { value: "p3", label: "Cara" },
37
+ { value: "p4", label: "Dan" },
38
+ ],
39
+ },
40
+ },
41
+ ]);
42
+
43
+ expect(
44
+ validateInteractionInputDomains(interaction, { players: ["p1"] }),
45
+ ).toEqual({
46
+ players: ["Choose at least 2 options."],
47
+ });
48
+ expect(
49
+ validateInteractionInputDomains(interaction, {
50
+ players: ["p1", "p2", "p3", "p4"],
51
+ }),
52
+ ).toEqual({
53
+ players: ["Choose at most 3 options."],
54
+ });
55
+ expect(
56
+ hasInteractionFieldErrors(
57
+ validateInteractionInputDomains(interaction, {
58
+ players: ["p1", "p2"],
59
+ }),
60
+ ),
61
+ ).toBe(false);
62
+ });
63
+
64
+ test("many target domains validate count, distinctness, and eligibility", () => {
65
+ const interaction = descriptor([
66
+ {
67
+ key: "cardIds",
68
+ kind: "card",
69
+ domain: {
70
+ type: "target",
71
+ targetKind: "card",
72
+ eligibleTargets: ["card-1", "card-2", "card-3"],
73
+ selection: {
74
+ mode: "many",
75
+ min: 2,
76
+ max: 3,
77
+ distinct: true,
78
+ },
79
+ },
80
+ },
81
+ ]);
82
+
83
+ expect(
84
+ validateInteractionInputDomains(interaction, { cardIds: ["card-1"] }),
85
+ ).toEqual({
86
+ cardIds: ["Choose at least 2 values."],
87
+ });
88
+ expect(
89
+ validateInteractionInputDomains(interaction, {
90
+ cardIds: ["card-1", "card-1"],
91
+ }),
92
+ ).toEqual({
93
+ cardIds: ["Choose each value only once."],
94
+ });
95
+ expect(
96
+ validateInteractionInputDomains(interaction, {
97
+ cardIds: ["card-1", "card-4"],
98
+ }),
99
+ ).toEqual({
100
+ cardIds: ["Selected target is not eligible."],
101
+ });
102
+ expect(
103
+ hasInteractionFieldErrors(
104
+ validateInteractionInputDomains(interaction, {
105
+ cardIds: ["card-1", "card-2", "card-3"],
106
+ }),
107
+ ),
108
+ ).toBe(false);
109
+ });
@@ -0,0 +1,331 @@
1
+ import type {
2
+ InteractionDescriptor,
3
+ InteractionInputDescriptor,
4
+ InputSelection,
5
+ } from "../types/plugin-state.js";
6
+
7
+ export type BoardTargetKind = "edge" | "vertex" | "space" | "tile";
8
+
9
+ export function interactionInputKeys(
10
+ descriptor: Pick<InteractionDescriptor, "inputs">,
11
+ ): string[] {
12
+ return descriptor.inputs.map((input) => input.key);
13
+ }
14
+
15
+ export function applyInteractionInputDefaults<
16
+ Params extends Record<string, unknown>,
17
+ >(
18
+ descriptor: Pick<InteractionDescriptor, "inputs">,
19
+ params: Readonly<Partial<Params>>,
20
+ ): Partial<Params> {
21
+ const next: Record<string, unknown> = { ...params };
22
+ for (const input of descriptor.inputs) {
23
+ if (next[input.key] !== undefined) continue;
24
+ if (!("defaultValue" in input)) continue;
25
+ next[input.key] = input.defaultValue;
26
+ }
27
+ return next as Partial<Params>;
28
+ }
29
+
30
+ export function validateInteractionInputDomains(
31
+ descriptor: Pick<InteractionDescriptor, "inputs">,
32
+ params: Readonly<Record<string, unknown>>,
33
+ ): Partial<Record<string, readonly string[]>> {
34
+ const fieldErrors: Record<string, string[]> = {};
35
+
36
+ for (const input of descriptor.inputs) {
37
+ const value = params[input.key];
38
+ if (value === undefined || value === null) continue;
39
+
40
+ const selectionErrors = validateInputSelection(input, value);
41
+ for (const error of selectionErrors) {
42
+ pushFieldError(fieldErrors, input.key, error);
43
+ }
44
+
45
+ if (input.domain.type === "choiceList") {
46
+ if (!Array.isArray(value)) {
47
+ pushFieldError(fieldErrors, input.key, "Expected a list of choices.");
48
+ continue;
49
+ }
50
+
51
+ const min = input.domain.min ?? 0;
52
+ const max =
53
+ input.domain.max ??
54
+ input.domain.choices?.length ??
55
+ Number.POSITIVE_INFINITY;
56
+ if (value.length < min) {
57
+ pushFieldError(
58
+ fieldErrors,
59
+ input.key,
60
+ `Choose at least ${min} ${pluralize("option", min)}.`,
61
+ );
62
+ }
63
+ if (value.length > max) {
64
+ pushFieldError(
65
+ fieldErrors,
66
+ input.key,
67
+ `Choose at most ${max} ${pluralize("option", max)}.`,
68
+ );
69
+ }
70
+ }
71
+
72
+ if (input.domain.type === "target") {
73
+ const values = valuesForSelection(input.domain.selection, value);
74
+ const eligible = input.domain.eligibleTargets;
75
+ if (eligible) {
76
+ for (const item of values) {
77
+ if (!eligible.includes(String(item))) {
78
+ pushFieldError(
79
+ fieldErrors,
80
+ input.key,
81
+ "Selected target is not eligible.",
82
+ );
83
+ break;
84
+ }
85
+ }
86
+ }
87
+ }
88
+ }
89
+
90
+ return fieldErrors;
91
+ }
92
+
93
+ export function isInputValueReady(
94
+ input: InteractionInputDescriptor,
95
+ value: unknown,
96
+ ): boolean {
97
+ if (value === undefined || value === null) return false;
98
+ const selection = input.domain.selection;
99
+ if (selection?.mode !== "many") return true;
100
+ return Array.isArray(value) && value.length >= (selection.min ?? 0);
101
+ }
102
+
103
+ export function isManyInput(input: InteractionInputDescriptor): boolean {
104
+ return input.domain.selection?.mode === "many";
105
+ }
106
+
107
+ export function maxSelectedForInput(
108
+ input: InteractionInputDescriptor,
109
+ ): number | undefined {
110
+ const selection = input.domain.selection;
111
+ return selection?.mode === "many" ? selection.max : undefined;
112
+ }
113
+
114
+ export function toggleManyValue(
115
+ current: unknown,
116
+ value: string,
117
+ selection: InputSelection,
118
+ ): string[] {
119
+ const previous = Array.isArray(current)
120
+ ? current.map((item) => String(item))
121
+ : [];
122
+ const existing = previous.indexOf(value);
123
+ if (existing >= 0) {
124
+ return previous.filter((item) => item !== value);
125
+ }
126
+ if (selection.max !== undefined && previous.length >= selection.max) {
127
+ return previous;
128
+ }
129
+ return [...previous, value];
130
+ }
131
+
132
+ export function isManyTargetSelectable(
133
+ input: InteractionInputDescriptor,
134
+ current: unknown,
135
+ targetId: string,
136
+ ): boolean {
137
+ const selection = input.domain.selection;
138
+ if (selection?.mode !== "many") return true;
139
+ const currentValues = Array.isArray(current)
140
+ ? current.map((item) => String(item))
141
+ : [];
142
+ if (currentValues.includes(targetId)) return true;
143
+ if (selection.distinct && currentValues.includes(targetId)) return false;
144
+ return selection.max === undefined || currentValues.length < selection.max;
145
+ }
146
+
147
+ export function mergeInteractionFieldErrors(
148
+ ...sources: Array<Partial<Record<string, readonly string[]>>>
149
+ ): Partial<Record<string, readonly string[]>> {
150
+ const merged: Record<string, string[]> = {};
151
+ for (const source of sources) {
152
+ for (const [key, messages] of Object.entries(source)) {
153
+ if (!messages || messages.length === 0) continue;
154
+ merged[key] = [...(merged[key] ?? []), ...messages];
155
+ }
156
+ }
157
+ return merged;
158
+ }
159
+
160
+ export function hasInteractionFieldErrors(
161
+ fieldErrors: Partial<Record<string, readonly string[]>>,
162
+ ): boolean {
163
+ return Object.values(fieldErrors).some(
164
+ (messages) => (messages?.length ?? 0) > 0,
165
+ );
166
+ }
167
+
168
+ export function inputByKey(
169
+ descriptor: Pick<InteractionDescriptor, "inputs">,
170
+ key: string,
171
+ ): InteractionInputDescriptor | undefined {
172
+ return descriptor.inputs.find((input) => input.key === key);
173
+ }
174
+
175
+ export function inputByTarget(
176
+ descriptor: Pick<InteractionDescriptor, "inputs">,
177
+ targetKind: BoardTargetKind | "card",
178
+ targetId: string,
179
+ ): InteractionInputDescriptor | null {
180
+ for (const input of descriptor.inputs) {
181
+ if (input.domain.type !== "target") continue;
182
+ if (input.domain.targetKind !== targetKind) continue;
183
+ if (input.domain.eligibleTargets?.includes(targetId)) return input;
184
+ }
185
+ return null;
186
+ }
187
+
188
+ export function eligibleTargetsForInput(
189
+ descriptor: Pick<InteractionDescriptor, "inputs">,
190
+ key: string,
191
+ ): readonly string[] | undefined {
192
+ const domain = inputByKey(descriptor, key)?.domain;
193
+ return domain?.type === "target" ? domain.eligibleTargets : undefined;
194
+ }
195
+
196
+ export function eligibleTargetsByInput(
197
+ descriptor: Pick<InteractionDescriptor, "inputs">,
198
+ ): Record<string, readonly string[]> {
199
+ return Object.fromEntries(
200
+ descriptor.inputs.flatMap((input) => {
201
+ const targets =
202
+ input.domain.type === "target"
203
+ ? input.domain.eligibleTargets
204
+ : undefined;
205
+ return targets ? [[input.key, targets]] : [];
206
+ }),
207
+ );
208
+ }
209
+
210
+ export function eligibleTargetsByBoardKind(
211
+ descriptor: Pick<InteractionDescriptor, "inputs">,
212
+ ): Partial<Record<BoardTargetKind, readonly string[]>> {
213
+ const result: Record<BoardTargetKind, Set<string>> = {
214
+ edge: new Set<string>(),
215
+ vertex: new Set<string>(),
216
+ space: new Set<string>(),
217
+ tile: new Set<string>(),
218
+ };
219
+ for (const input of descriptor.inputs) {
220
+ if (input.domain.type !== "target") continue;
221
+ const targetKind = input.domain.targetKind;
222
+ if (!isBoardTargetKind(targetKind)) continue;
223
+ for (const targetId of input.domain.eligibleTargets ?? []) {
224
+ result[targetKind].add(targetId);
225
+ }
226
+ }
227
+ return Object.fromEntries(
228
+ Object.entries(result).flatMap(([kind, ids]) =>
229
+ ids.size > 0 ? [[kind, [...ids]]] : [],
230
+ ),
231
+ ) as Partial<Record<BoardTargetKind, readonly string[]>>;
232
+ }
233
+
234
+ export function hasBoardTargetInput(
235
+ descriptor: Pick<InteractionDescriptor, "inputs">,
236
+ ): boolean {
237
+ return Object.keys(eligibleTargetsByBoardKind(descriptor)).length > 0;
238
+ }
239
+
240
+ export function hasCardTargetInput(
241
+ descriptor: Pick<InteractionDescriptor, "inputs">,
242
+ ): boolean {
243
+ return descriptor.inputs.some(
244
+ (input) =>
245
+ input.domain.type === "target" && input.domain.targetKind === "card",
246
+ );
247
+ }
248
+
249
+ export function interactionArmScope(
250
+ descriptor: Pick<
251
+ InteractionDescriptor,
252
+ "inputs" | "interactionKey" | "zoneId"
253
+ >,
254
+ ): string {
255
+ const byKind = eligibleTargetsByBoardKind(descriptor);
256
+ const boardKinds = (Object.keys(byKind) as BoardTargetKind[]).filter(
257
+ (kind) => byKind[kind] !== undefined,
258
+ );
259
+ if (boardKinds.length === 1) return `board:${boardKinds[0]}`;
260
+ if (boardKinds.length > 1) return "board";
261
+ if (descriptor.zoneId) return `zone:${descriptor.zoneId}`;
262
+ return `interaction:${descriptor.interactionKey}`;
263
+ }
264
+
265
+ export function inputKeyForTarget(
266
+ descriptor: Pick<InteractionDescriptor, "inputs">,
267
+ targetKind: BoardTargetKind | "card",
268
+ targetId: string,
269
+ ): string | null {
270
+ return inputByTarget(descriptor, targetKind, targetId)?.key ?? null;
271
+ }
272
+
273
+ function validateInputSelection(
274
+ input: InteractionInputDescriptor,
275
+ value: unknown,
276
+ ): string[] {
277
+ const selection = input.domain.selection;
278
+ if (selection?.mode !== "many") return [];
279
+ if (!Array.isArray(value)) return ["Expected a list of values."];
280
+ const errors: string[] = [];
281
+ const min = selection.min ?? 0;
282
+ if (value.length < min) {
283
+ errors.push(`Choose at least ${min} ${pluralize("value", min)}.`);
284
+ }
285
+ if (selection.max !== undefined && value.length > selection.max) {
286
+ errors.push(
287
+ `Choose at most ${selection.max} ${pluralize("value", selection.max)}.`,
288
+ );
289
+ }
290
+ if (selection.distinct) {
291
+ const seen = new Set<string>();
292
+ for (const item of value) {
293
+ const key = String(item);
294
+ if (seen.has(key)) {
295
+ errors.push("Choose each value only once.");
296
+ break;
297
+ }
298
+ seen.add(key);
299
+ }
300
+ }
301
+ return errors;
302
+ }
303
+
304
+ function valuesForSelection(
305
+ selection: InputSelection | undefined,
306
+ value: unknown,
307
+ ): readonly unknown[] {
308
+ if (selection?.mode === "many") return Array.isArray(value) ? value : [];
309
+ return [value];
310
+ }
311
+
312
+ function isBoardTargetKind(value: unknown): value is BoardTargetKind {
313
+ return (
314
+ value === "edge" ||
315
+ value === "vertex" ||
316
+ value === "space" ||
317
+ value === "tile"
318
+ );
319
+ }
320
+
321
+ function pushFieldError(
322
+ fieldErrors: Record<string, string[]>,
323
+ key: string,
324
+ message: string,
325
+ ): void {
326
+ fieldErrors[key] = [...(fieldErrors[key] ?? []), message];
327
+ }
328
+
329
+ function pluralize(word: string, count: number): string {
330
+ return count === 1 ? word : `${word}s`;
331
+ }
@@ -0,0 +1,23 @@
1
+ import type { InteractionDescriptor } from "../types/plugin-state.js";
2
+
3
+ export function humanizeInteractionId(id: string): string {
4
+ if (!id) return id;
5
+ const withSpaces = id
6
+ .replace(/[-_]+/g, " ")
7
+ .replace(/([a-z0-9])([A-Z])/g, "$1 $2")
8
+ .replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2")
9
+ .trim();
10
+ if (!withSpaces) return id;
11
+ return withSpaces
12
+ .split(/\s+/)
13
+ .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
14
+ .join(" ");
15
+ }
16
+
17
+ export function interactionLabel(
18
+ descriptor: Pick<InteractionDescriptor, "interactionId" | "interactionKey">,
19
+ ): string {
20
+ return humanizeInteractionId(
21
+ descriptor.interactionId || descriptor.interactionKey,
22
+ );
23
+ }
@@ -0,0 +1,59 @@
1
+ import type { InteractionHandleStatus } from "../hooks/useInteractionHandle.js";
2
+ import type { InteractionDescriptor } from "../types/plugin-state.js";
3
+
4
+ export type InteractionActionState =
5
+ | "available"
6
+ | "unavailable"
7
+ | "submitting"
8
+ | "submitted";
9
+
10
+ export type InteractionDisabledReason =
11
+ | "unavailable"
12
+ | "selection-limit"
13
+ | "submitting"
14
+ | "submitted";
15
+
16
+ export interface InteractionStatusSnapshot {
17
+ status: InteractionHandleStatus;
18
+ actionState: InteractionActionState;
19
+ disabled: boolean;
20
+ disabledReason?: InteractionDisabledReason;
21
+ }
22
+
23
+ export function interactionStatusSnapshot({
24
+ descriptor,
25
+ status,
26
+ }: {
27
+ descriptor: InteractionDescriptor;
28
+ status: InteractionHandleStatus;
29
+ }): InteractionStatusSnapshot {
30
+ if (status === "submitted") {
31
+ return {
32
+ status,
33
+ actionState: "submitted",
34
+ disabled: true,
35
+ disabledReason: "submitted",
36
+ };
37
+ }
38
+ if (status === "submitting") {
39
+ return {
40
+ status,
41
+ actionState: "submitting",
42
+ disabled: true,
43
+ disabledReason: "submitting",
44
+ };
45
+ }
46
+ if (descriptor.available === false) {
47
+ return {
48
+ status,
49
+ actionState: "unavailable",
50
+ disabled: true,
51
+ disabledReason: "unavailable",
52
+ };
53
+ }
54
+ return {
55
+ status,
56
+ actionState: "available",
57
+ disabled: false,
58
+ };
59
+ }