@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,458 @@
1
+ import type { CSSProperties, ReactNode } from "react";
2
+ import { useSeatInbox } from "../../hooks/useSeatInbox.js";
3
+ import {
4
+ useInteractionHandle,
5
+ type InteractionHandle,
6
+ } from "../../hooks/useInteractionHandle.js";
7
+ import { useTheme } from "../../theme/ThemeProvider.js";
8
+ import type { InteractionDescriptor } from "../../types/plugin-state.js";
9
+ import { DefaultInteractionButton } from "./internal/DefaultInteractionButton.js";
10
+ import { MoreActions } from "../MoreActions.js";
11
+ import type {
12
+ InteractionDefaultedKeysOf,
13
+ InteractionParamsByKeyShape,
14
+ InteractionParamsOf,
15
+ SurfaceRenderMap,
16
+ } from "./types.js";
17
+
18
+ /**
19
+ * Resolved salience tier for a panel interaction. Authors set
20
+ * `descriptor.salience` directly; when omitted we derive a sensible
21
+ * default from `descriptor.emphasis` so existing workspaces inherit
22
+ * the new ordering / disclosure behaviour without being touched.
23
+ *
24
+ * - `descriptor.salience === "hero"` → `hero`
25
+ * - `descriptor.salience === "tertiary"` → `tertiary`
26
+ * - `descriptor.emphasis === "primary"` → `hero`
27
+ * - `descriptor.emphasis === "destructive"` → `tertiary`
28
+ * - everything else → `secondary` (the default tier)
29
+ */
30
+ export type PanelSalience = "hero" | "secondary" | "tertiary";
31
+
32
+ export interface PanelSurfaceProps<
33
+ I extends string = never,
34
+ ParamsByKey extends Partial<InteractionParamsByKeyShape> = {},
35
+ > {
36
+ /**
37
+ * Optional per-interaction overrides. Omit entirely to use the default
38
+ * renderer (`DefaultInteractionButton`) for every interaction; supply a
39
+ * partial map to replace the default UI for specific interaction ids.
40
+ */
41
+ render?: SurfaceRenderMap<I, ParamsByKey>;
42
+ /**
43
+ * Fallback renderer for interactions without a `render` entry. Defaults
44
+ * to the built-in `DefaultInteractionButton` which honours metadata
45
+ * (`icon`, `label`, `emphasis`, `unavailableReason`).
46
+ */
47
+ renderItem?: (
48
+ descriptor: InteractionDescriptor<I>,
49
+ handle: InteractionHandle<
50
+ InteractionParamsOf<ParamsByKey, I>,
51
+ InteractionDefaultedKeysOf<ParamsByKey, I>
52
+ >,
53
+ ) => ReactNode;
54
+ /** Shown when no panel interactions are available. */
55
+ empty?: ReactNode;
56
+ /**
57
+ * Optional grouping function. Defaults to `descriptor.group`; authors
58
+ * can override to cluster interactions differently. Returning
59
+ * `undefined` keeps the interaction in the ungrouped tail cluster.
60
+ */
61
+ groupBy?: (descriptor: InteractionDescriptor<I>) => string | undefined;
62
+ /**
63
+ * Override the default salience derivation. Receives the descriptor
64
+ * and returns the tier it should occupy. Use to demote something the
65
+ * authoring layer mis-tagged as `emphasis: "primary"` without
66
+ * changing the upstream contract.
67
+ */
68
+ salienceFor?: (descriptor: InteractionDescriptor<I>) => PanelSalience;
69
+ /**
70
+ * Maximum number of `secondary`-tier items to render directly in the
71
+ * panel. Excess secondaries spill into the {@link MoreActions}
72
+ * disclosure (alongside the always-disclosed `tertiary` tier).
73
+ * Defaults to `Infinity` — secondaries stay visible. Lower this on
74
+ * dense HUDs to fight Hick's Law.
75
+ *
76
+ * Hero items are never spilled, so a panel with three hero entries
77
+ * and `maxVisibleSecondary: 0` still renders three buttons inline
78
+ * plus the disclosure.
79
+ */
80
+ maxVisibleSecondary?: number;
81
+ /**
82
+ * Label for the disclosure toggle. Defaults to `"More"`. Pass a
83
+ * workspace-specific copy ("Advanced", "Manage", …) when the
84
+ * generic label feels wrong.
85
+ */
86
+ moreActionsLabel?: string;
87
+ /** Interaction keys intentionally rendered elsewhere, such as auto primary actions. */
88
+ excludeInteractionKeys?: readonly string[];
89
+ /**
90
+ * Render unavailable interactions as disabled items. Defaults to false so
91
+ * stale-step actions do not compete with legal actions.
92
+ */
93
+ showUnavailable?: boolean;
94
+ /**
95
+ * Layout overrides for the default container. Useful for tightly
96
+ * constrained mobile layouts. When the caller supplies their own
97
+ * `render` for every interaction they can ignore these entirely.
98
+ */
99
+ layout?: {
100
+ direction?: "row" | "column";
101
+ wrap?: boolean;
102
+ gap?: CSSProperties["gap"];
103
+ align?: CSSProperties["alignItems"];
104
+ justify?: CSSProperties["justifyContent"];
105
+ };
106
+ }
107
+
108
+ const SALIENCE_RANK: Record<PanelSalience, number> = {
109
+ hero: 0,
110
+ secondary: 1,
111
+ tertiary: 2,
112
+ };
113
+
114
+ /**
115
+ * Default salience resolver — see {@link PanelSalience}. Exported so
116
+ * authors who want to slightly tweak the policy can compose with it
117
+ * (`salienceFor: (d) => d.id === "x" ? "hero" : defaultPanelSalience(d)`).
118
+ */
119
+ export function defaultPanelSalience(
120
+ _descriptor: InteractionDescriptor,
121
+ ): PanelSalience {
122
+ return "secondary";
123
+ }
124
+
125
+ // `align: "flex-start"` is deliberate. Panel items are heterogeneous —
126
+ // a `DefaultInteractionButton` sits next to authored cards that can
127
+ // expand into multi-row draft forms (e.g. an offer-trade card). With
128
+ // `stretch` the short buttons get dragged to the tallest sibling's
129
+ // height and render as floor-to-ceiling bars next to the expanded form.
130
+ // Authors who *do* want uniform heights can opt in via `layout.align`.
131
+ const defaultLayout: Required<
132
+ NonNullable<PanelSurfaceProps<string>["layout"]>
133
+ > = {
134
+ direction: "row",
135
+ wrap: true,
136
+ gap: "8px",
137
+ align: "flex-start",
138
+ justify: "flex-start",
139
+ };
140
+
141
+ /**
142
+ * Default renderer for `surface: "panel"` interactions.
143
+ *
144
+ * Visual styling comes entirely from the active {@link useTheme}; mount
145
+ * `<ThemeProvider theme={...}/>` to swap the look. Per-interaction overrides
146
+ * via `render` are the escape hatch when a specific interaction needs bespoke
147
+ * UI.
148
+ *
149
+ * Salience policy
150
+ * ===============
151
+ * Each descriptor is assigned a {@link PanelSalience} via
152
+ * {@link defaultPanelSalience} (override with the `salienceFor` prop).
153
+ * The panel sorts groups so `hero` items render first, then
154
+ * `secondary`, then `tertiary` — and the `tertiary` cluster (plus any
155
+ * spill from `maxVisibleSecondary`) lives behind a {@link MoreActions}
156
+ * disclosure so a crowded panel doesn't drown the player in choices
157
+ * (Hick's Law). Groups stay contiguous: a group inherits the highest
158
+ * salience among its members so a hero+secondary cluster doesn't get
159
+ * split across the disclosure boundary.
160
+ */
161
+ export function PanelSurface<
162
+ I extends string = never,
163
+ ParamsByKey extends Partial<InteractionParamsByKeyShape> = {},
164
+ >({
165
+ render,
166
+ renderItem,
167
+ empty = null,
168
+ groupBy = () => undefined,
169
+ salienceFor,
170
+ maxVisibleSecondary = Number.POSITIVE_INFINITY,
171
+ moreActionsLabel,
172
+ excludeInteractionKeys,
173
+ showUnavailable = false,
174
+ layout,
175
+ }: PanelSurfaceProps<I, ParamsByKey>) {
176
+ const inbox = useSeatInbox();
177
+ const excluded = new Set(excludeInteractionKeys ?? []);
178
+ const items = (
179
+ (inbox.bySurface.panel ?? []) as ReadonlyArray<InteractionDescriptor<I>>
180
+ ).filter(
181
+ (descriptor) =>
182
+ !excluded.has(descriptor.interactionKey) &&
183
+ (showUnavailable || descriptor.available),
184
+ );
185
+ if (items.length === 0) return <>{empty}</>;
186
+
187
+ const resolvedLayout = { ...defaultLayout, ...(layout ?? {}) };
188
+ const resolveSalience: (
189
+ descriptor: InteractionDescriptor<I>,
190
+ ) => PanelSalience = salienceFor ?? defaultPanelSalience;
191
+
192
+ // Compute groups first (preserves authored cohesion), then assign
193
+ // each group a tier from its highest-salience member, then sort by
194
+ // tier while keeping members in their original order.
195
+ const grouped = groupInteractions<I>(items, groupBy, resolveSalience);
196
+ const sorted = [...grouped].sort((a, b) => {
197
+ const tierDiff = SALIENCE_RANK[a.tier] - SALIENCE_RANK[b.tier];
198
+ if (tierDiff !== 0) return tierDiff;
199
+ // Same tier — preserve authored order via the cached index.
200
+ return a.firstIndex - b.firstIndex;
201
+ });
202
+
203
+ // Decide which groups stay in the main row vs. spill into the
204
+ // disclosure. Hero groups always stay; tertiary groups always
205
+ // spill; secondary groups spill once we've already shown
206
+ // `maxVisibleSecondary` of them. A group counts as 1 toward the
207
+ // budget regardless of how many descriptors it contains — losing
208
+ // half a "build" cluster would be more confusing than rendering
209
+ // the whole sub-row.
210
+ const visible: typeof sorted = [];
211
+ const disclosed: typeof sorted = [];
212
+ let secondariesShown = 0;
213
+ for (const group of sorted) {
214
+ if (group.tier === "hero") {
215
+ visible.push(group);
216
+ continue;
217
+ }
218
+ if (group.tier === "tertiary") {
219
+ disclosed.push(group);
220
+ continue;
221
+ }
222
+ if (secondariesShown < maxVisibleSecondary) {
223
+ visible.push(group);
224
+ secondariesShown += 1;
225
+ } else {
226
+ disclosed.push(group);
227
+ }
228
+ }
229
+
230
+ // Count the underlying descriptors so the disclosure badge reads
231
+ // "More (3)" not "More (1 group)".
232
+ const disclosedCount = disclosed.reduce(
233
+ (sum, group) => sum + group.interactions.length,
234
+ 0,
235
+ );
236
+
237
+ return (
238
+ <div
239
+ role="toolbar"
240
+ aria-label="Panel actions"
241
+ data-shell-slot="panel-actions"
242
+ style={{
243
+ display: "flex",
244
+ flexDirection: resolvedLayout.direction,
245
+ flexWrap: resolvedLayout.wrap ? "wrap" : "nowrap",
246
+ gap: resolvedLayout.gap,
247
+ alignItems: resolvedLayout.align,
248
+ justifyContent: resolvedLayout.justify,
249
+ }}
250
+ >
251
+ {visible.map((group) => (
252
+ <PanelGroup<I, ParamsByKey>
253
+ key={group.id}
254
+ group={group}
255
+ render={render}
256
+ renderItem={renderItem}
257
+ />
258
+ ))}
259
+ {disclosed.length > 0 ? (
260
+ <MoreActions label={moreActionsLabel} count={disclosedCount}>
261
+ {disclosed.map((group) => (
262
+ <PanelGroup<I, ParamsByKey>
263
+ key={group.id}
264
+ group={group}
265
+ render={render}
266
+ renderItem={renderItem}
267
+ />
268
+ ))}
269
+ </MoreActions>
270
+ ) : null}
271
+ </div>
272
+ );
273
+ }
274
+
275
+ interface PanelGroupDescriptor<I extends string> {
276
+ readonly id: string;
277
+ readonly interactions: ReadonlyArray<InteractionDescriptor<I>>;
278
+ readonly grouped: boolean;
279
+ readonly tier: PanelSalience;
280
+ /** Original index of the first member, used to preserve authored
281
+ * order when sort keys tie. */
282
+ readonly firstIndex: number;
283
+ }
284
+
285
+ function groupInteractions<I extends string>(
286
+ items: ReadonlyArray<InteractionDescriptor<I>>,
287
+ groupBy: (descriptor: InteractionDescriptor<I>) => string | undefined,
288
+ resolveSalience: (descriptor: InteractionDescriptor<I>) => PanelSalience,
289
+ ): Array<PanelGroupDescriptor<I>> {
290
+ // Two-pass build so each group's tier reflects its highest-salience
291
+ // member regardless of arrival order. Pass 1 collects buckets while
292
+ // preserving the order in which each *cluster* first appears (for
293
+ // the eventual `firstIndex` tie-break). Pass 2 freezes the buckets
294
+ // into the immutable shape `PanelGroupDescriptor` advertises.
295
+ interface MutableBucket {
296
+ id: string;
297
+ grouped: boolean;
298
+ interactions: Array<InteractionDescriptor<I>>;
299
+ tier: PanelSalience;
300
+ firstIndex: number;
301
+ }
302
+ const ordered: MutableBucket[] = [];
303
+ const byGroup = new Map<string, MutableBucket>();
304
+
305
+ items.forEach((descriptor, index) => {
306
+ const tier = resolveSalience(descriptor);
307
+ const key = groupBy(descriptor);
308
+ if (key === undefined) {
309
+ ordered.push({
310
+ id: `solo:${descriptor.interactionId}`,
311
+ grouped: false,
312
+ interactions: [descriptor],
313
+ tier,
314
+ firstIndex: index,
315
+ });
316
+ return;
317
+ }
318
+ const bucket = byGroup.get(key);
319
+ if (bucket) {
320
+ bucket.interactions.push(descriptor);
321
+ if (SALIENCE_RANK[tier] < SALIENCE_RANK[bucket.tier]) {
322
+ bucket.tier = tier;
323
+ }
324
+ return;
325
+ }
326
+ const fresh: MutableBucket = {
327
+ id: `group:${key}`,
328
+ grouped: true,
329
+ interactions: [descriptor],
330
+ tier,
331
+ firstIndex: index,
332
+ };
333
+ byGroup.set(key, fresh);
334
+ ordered.push(fresh);
335
+ });
336
+
337
+ return ordered.map((bucket) => ({
338
+ id: bucket.id,
339
+ interactions: bucket.interactions,
340
+ grouped: bucket.grouped,
341
+ tier: bucket.tier,
342
+ firstIndex: bucket.firstIndex,
343
+ }));
344
+ }
345
+
346
+ function PanelGroup<
347
+ I extends string,
348
+ ParamsByKey extends Partial<InteractionParamsByKeyShape> = {},
349
+ >({
350
+ group,
351
+ render,
352
+ renderItem,
353
+ }: {
354
+ group: PanelGroupDescriptor<I>;
355
+ render?: SurfaceRenderMap<I, ParamsByKey>;
356
+ renderItem?: (
357
+ descriptor: InteractionDescriptor<I>,
358
+ handle: InteractionHandle<
359
+ InteractionParamsOf<ParamsByKey, I>,
360
+ InteractionDefaultedKeysOf<ParamsByKey, I>
361
+ >,
362
+ ) => ReactNode;
363
+ }) {
364
+ const theme = useTheme();
365
+ if (!group.grouped || group.interactions.length === 1) {
366
+ return (
367
+ <>
368
+ {group.interactions.map((descriptor) => (
369
+ <PanelItem<I, ParamsByKey>
370
+ key={descriptor.interactionKey}
371
+ descriptor={descriptor}
372
+ render={render}
373
+ renderItem={renderItem}
374
+ tier={group.tier}
375
+ />
376
+ ))}
377
+ </>
378
+ );
379
+ }
380
+ return (
381
+ <div
382
+ data-panel-group={group.id}
383
+ data-panel-tier={group.tier}
384
+ style={{
385
+ display: "inline-flex",
386
+ gap: theme.space[1],
387
+ padding: theme.space[1],
388
+ borderRadius: theme.radius.lg,
389
+ background: theme.semantic.surface.inset,
390
+ }}
391
+ >
392
+ {group.interactions.map((descriptor) => (
393
+ <PanelItem<I, ParamsByKey>
394
+ key={descriptor.interactionKey}
395
+ descriptor={descriptor}
396
+ render={render}
397
+ renderItem={renderItem}
398
+ compact
399
+ tier={group.tier}
400
+ />
401
+ ))}
402
+ </div>
403
+ );
404
+ }
405
+
406
+ function PanelItem<
407
+ I extends string,
408
+ ParamsByKey extends Partial<InteractionParamsByKeyShape> = {},
409
+ >({
410
+ descriptor,
411
+ render,
412
+ renderItem,
413
+ compact,
414
+ tier,
415
+ }: {
416
+ descriptor: InteractionDescriptor<I>;
417
+ render?: SurfaceRenderMap<I, ParamsByKey>;
418
+ renderItem?: (
419
+ descriptor: InteractionDescriptor<I>,
420
+ handle: InteractionHandle<
421
+ InteractionParamsOf<ParamsByKey, I>,
422
+ InteractionDefaultedKeysOf<ParamsByKey, I>
423
+ >,
424
+ ) => ReactNode;
425
+ compact?: boolean;
426
+ tier: PanelSalience;
427
+ }) {
428
+ const handle = useInteractionHandle<
429
+ InteractionParamsOf<ParamsByKey, I>,
430
+ InteractionDefaultedKeysOf<ParamsByKey, I>
431
+ >(descriptor);
432
+ const override = render?.[descriptor.interactionKey] as
433
+ | ((
434
+ descriptor: InteractionDescriptor<I>,
435
+ handle: InteractionHandle<
436
+ InteractionParamsOf<ParamsByKey, I>,
437
+ InteractionDefaultedKeysOf<ParamsByKey, I>
438
+ >,
439
+ ) => ReactNode)
440
+ | undefined;
441
+ if (override) return <>{override(descriptor, handle)}</>;
442
+ if (renderItem) return <>{renderItem(descriptor, handle)}</>;
443
+ // Salience-driven sizing: hero buttons use the `lg` size so they
444
+ // outweigh the `secondary` tier next to them. Tertiary items render
445
+ // inside the disclosure where the smaller `sm` size keeps the
446
+ // disclosed cluster from feeling like a second main panel.
447
+ const size: "sm" | "md" | "lg" =
448
+ compact || tier === "tertiary" ? "sm" : tier === "hero" ? "lg" : "md";
449
+ return (
450
+ <DefaultInteractionButton
451
+ descriptor={descriptor}
452
+ handle={handle}
453
+ compact={compact}
454
+ size={size}
455
+ data-panel-tier={tier}
456
+ />
457
+ );
458
+ }