@dreamboard-games/sdk 0.2.0

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 (369) hide show
  1. package/LICENSE.md +96 -0
  2. package/README.md +12 -0
  3. package/dist/HandView-ncJIVLhN.d.ts +193 -0
  4. package/dist/ResourceCounter-CTREyF73.d.ts +102 -0
  5. package/dist/ThemeProvider-fy0_QzgO.d.ts +99 -0
  6. package/dist/bundle-TIZcw8LB.d.ts +281 -0
  7. package/dist/cards-Sl3b40Mv.d.ts +13 -0
  8. package/dist/chunk-7YAHLYBR.js +481 -0
  9. package/dist/chunk-7YAHLYBR.js.map +1 -0
  10. package/dist/chunk-FDNZTDD6.js +8085 -0
  11. package/dist/chunk-FDNZTDD6.js.map +1 -0
  12. package/dist/chunk-GKKBPPSW.js +598 -0
  13. package/dist/chunk-GKKBPPSW.js.map +1 -0
  14. package/dist/chunk-I46YJSOD.js +1 -0
  15. package/dist/chunk-I46YJSOD.js.map +1 -0
  16. package/dist/chunk-KAELH4KC.js +104 -0
  17. package/dist/chunk-KAELH4KC.js.map +1 -0
  18. package/dist/chunk-PZ5AY32C.js +10 -0
  19. package/dist/chunk-PZ5AY32C.js.map +1 -0
  20. package/dist/chunk-T3ZKNUZ7.js +1 -0
  21. package/dist/chunk-T3ZKNUZ7.js.map +1 -0
  22. package/dist/chunk-T52J5RMF.js +1 -0
  23. package/dist/chunk-T52J5RMF.js.map +1 -0
  24. package/dist/chunk-TDSWKVZ4.js +5401 -0
  25. package/dist/chunk-TDSWKVZ4.js.map +1 -0
  26. package/dist/chunk-U5C6BONG.js +34 -0
  27. package/dist/chunk-U5C6BONG.js.map +1 -0
  28. package/dist/chunk-VDXOF4FW.js +69 -0
  29. package/dist/chunk-VDXOF4FW.js.map +1 -0
  30. package/dist/chunk-VFTAA4WO.js +115 -0
  31. package/dist/chunk-VFTAA4WO.js.map +1 -0
  32. package/dist/chunk-WN74KVNY.js +17 -0
  33. package/dist/chunk-WN74KVNY.js.map +1 -0
  34. package/dist/chunk-WYPQ3GG5.js +10990 -0
  35. package/dist/chunk-WYPQ3GG5.js.map +1 -0
  36. package/dist/components-D5ZRE2Hl.d.ts +1451 -0
  37. package/dist/generated/runtime/primitives.d.ts +12 -0
  38. package/dist/generated/runtime/primitives.js +180 -0
  39. package/dist/generated/runtime/primitives.js.map +1 -0
  40. package/dist/generated/runtime-api.d.ts +3 -0
  41. package/dist/generated/runtime-api.js +2 -0
  42. package/dist/generated/runtime-api.js.map +1 -0
  43. package/dist/generated/runtime.d.ts +14 -0
  44. package/dist/generated/runtime.js +18 -0
  45. package/dist/generated/runtime.js.map +1 -0
  46. package/dist/generated/workspace-contract.d.ts +14 -0
  47. package/dist/generated/workspace-contract.js +14 -0
  48. package/dist/generated/workspace-contract.js.map +1 -0
  49. package/dist/hex-board-view-D_07hO6O.d.ts +933 -0
  50. package/dist/hex-color-MhOyuY-o.d.ts +8 -0
  51. package/dist/index-BwqPQtBu.d.ts +1433 -0
  52. package/dist/index.d.ts +1 -0
  53. package/dist/index.js +12 -0
  54. package/dist/index.js.map +1 -0
  55. package/dist/infrastructure/reducer-bundle-abi.d.ts +1083 -0
  56. package/dist/infrastructure/reducer-bundle-abi.js +14 -0
  57. package/dist/infrastructure/reducer-bundle-abi.js.map +1 -0
  58. package/dist/infrastructure/workspace-codegen.d.ts +53 -0
  59. package/dist/infrastructure/workspace-codegen.js +44 -0
  60. package/dist/infrastructure/workspace-codegen.js.map +1 -0
  61. package/dist/manifest-contract-BNHVGFtU.d.ts +9 -0
  62. package/dist/package-set.d.ts +13 -0
  63. package/dist/package-set.js +12 -0
  64. package/dist/package-set.js.map +1 -0
  65. package/dist/primitive-props-DpKs-GCr.d.ts +11 -0
  66. package/dist/reducer.d.ts +3786 -0
  67. package/dist/reducer.js +8131 -0
  68. package/dist/reducer.js.map +1 -0
  69. package/dist/runtime/primitives.d.ts +226 -0
  70. package/dist/runtime/primitives.js +180 -0
  71. package/dist/runtime/primitives.js.map +1 -0
  72. package/dist/runtime/types/runtime-api.d.ts +1 -0
  73. package/dist/runtime/types/runtime-api.js +2 -0
  74. package/dist/runtime/types/runtime-api.js.map +1 -0
  75. package/dist/runtime/workspace-contract.d.ts +172 -0
  76. package/dist/runtime/workspace-contract.js +14 -0
  77. package/dist/runtime/workspace-contract.js.map +1 -0
  78. package/dist/runtime-api-3dshj6kK.d.ts +101 -0
  79. package/dist/runtime-api-DWxvTr-O.d.ts +379 -0
  80. package/dist/runtime.d.ts +58 -0
  81. package/dist/runtime.js +13 -0
  82. package/dist/runtime.js.map +1 -0
  83. package/dist/slots-1GPGihk8.d.ts +8 -0
  84. package/dist/testing.d.ts +149 -0
  85. package/dist/testing.js +513 -0
  86. package/dist/testing.js.map +1 -0
  87. package/dist/types.d.ts +496 -0
  88. package/dist/types.js +28 -0
  89. package/dist/types.js.map +1 -0
  90. package/dist/ui/components.d.ts +16 -0
  91. package/dist/ui/components.js +192 -0
  92. package/dist/ui/components.js.map +1 -0
  93. package/dist/ui/defaults.d.ts +19 -0
  94. package/dist/ui/defaults.js +104 -0
  95. package/dist/ui/defaults.js.map +1 -0
  96. package/dist/ui/plugin-styles.css +250 -0
  97. package/dist/ui/types/player-state.d.ts +365 -0
  98. package/dist/ui/types/player-state.js +1 -0
  99. package/dist/ui/types/player-state.js.map +1 -0
  100. package/dist/ui-contract-iQfTtUSL.d.ts +1161 -0
  101. package/dist/ui.d.ts +320 -0
  102. package/dist/ui.js +253 -0
  103. package/dist/ui.js.map +1 -0
  104. package/package.json +199 -0
  105. package/src/generated/reducer-contract/builders.ts +90 -0
  106. package/src/generated/reducer-contract/version.ts +9 -0
  107. package/src/generated/reducer-contract/wire.ts +100 -0
  108. package/src/generated/reducer-contract/zod.ts +101 -0
  109. package/src/generated/runtime/primitives.ts +2 -0
  110. package/src/generated/runtime-api.ts +5 -0
  111. package/src/generated/runtime.ts +35 -0
  112. package/src/generated/workspace-contract.ts +2 -0
  113. package/src/index.ts +7 -0
  114. package/src/infrastructure/reducer-bundle-abi.ts +8 -0
  115. package/src/infrastructure/reducer-contract/bundle.ts +37 -0
  116. package/src/infrastructure/workspace-codegen/hex-geometry.ts +69 -0
  117. package/src/infrastructure/workspace-codegen/index.ts +64 -0
  118. package/src/infrastructure/workspace-codegen/manifest-contract.ts +6632 -0
  119. package/src/infrastructure/workspace-codegen/manifest-validation.ts +795 -0
  120. package/src/infrastructure/workspace-codegen/ownership.ts +131 -0
  121. package/src/infrastructure/workspace-codegen/preset-card-sets.ts +169 -0
  122. package/src/infrastructure/workspace-codegen/seeds.ts +1705 -0
  123. package/src/infrastructure/workspace-codegen.ts +1 -0
  124. package/src/package-set.ts +19 -0
  125. package/src/reducer/authoring/contract.ts +157 -0
  126. package/src/reducer/authoring/effect.ts +224 -0
  127. package/src/reducer/authoring/game.ts +23 -0
  128. package/src/reducer/authoring/interaction.ts +98 -0
  129. package/src/reducer/authoring/phase.ts +300 -0
  130. package/src/reducer/authoring/types.ts +70 -0
  131. package/src/reducer/authoring/validation.ts +382 -0
  132. package/src/reducer/authoring/view-stage.ts +68 -0
  133. package/src/reducer/authoring.ts +29 -0
  134. package/src/reducer/bundle/ingress-bundle.ts +491 -0
  135. package/src/reducer/bundle/trusted/engine-instruction-resolver.ts +254 -0
  136. package/src/reducer/bundle/trusted/flow-instruction-resolver.ts +73 -0
  137. package/src/reducer/bundle/trusted/instruction-runner.ts +414 -0
  138. package/src/reducer/bundle/trusted/interaction-authorization.ts +137 -0
  139. package/src/reducer/bundle/trusted/interaction-collectors.ts +859 -0
  140. package/src/reducer/bundle/trusted/interaction-decision.ts +747 -0
  141. package/src/reducer/bundle/trusted/interaction-resolver.ts +95 -0
  142. package/src/reducer/bundle/trusted/interaction-types.ts +171 -0
  143. package/src/reducer/bundle/trusted/lifecycle-runner.ts +427 -0
  144. package/src/reducer/bundle/trusted/projection-builder.ts +356 -0
  145. package/src/reducer/bundle/trusted/projection-context.ts +39 -0
  146. package/src/reducer/bundle/trusted/rng-sampler.ts +150 -0
  147. package/src/reducer/bundle/trusted/runtime-registry.ts +120 -0
  148. package/src/reducer/bundle/trusted/runtime-scope.ts +336 -0
  149. package/src/reducer/bundle/trusted/simultaneous-player.ts +97 -0
  150. package/src/reducer/bundle/trusted/stage-resolver.ts +87 -0
  151. package/src/reducer/bundle/trusted/static-projection.ts +116 -0
  152. package/src/reducer/bundle/trusted/trusted-runtime-args.ts +97 -0
  153. package/src/reducer/bundle/trusted/trusted-runtime-result.ts +39 -0
  154. package/src/reducer/bundle/trusted/trusted-setup-profiles.ts +43 -0
  155. package/src/reducer/bundle/trusted/trusted-state-codec.ts +48 -0
  156. package/src/reducer/bundle/trusted-bundle.ts +97 -0
  157. package/src/reducer/bundle/types.ts +171 -0
  158. package/src/reducer/bundle.ts +2 -0
  159. package/src/reducer/client-param-schemas.ts +57 -0
  160. package/src/reducer/compose.ts +34 -0
  161. package/src/reducer/core/runtime-input.ts +30 -0
  162. package/src/reducer/core/runtime-instruction.ts +59 -0
  163. package/src/reducer/core/types.ts +62 -0
  164. package/src/reducer/definition-index.ts +277 -0
  165. package/src/reducer/derived.ts +106 -0
  166. package/src/reducer/effects.ts +92 -0
  167. package/src/reducer/engine/runtime-instruction-engine.ts +155 -0
  168. package/src/reducer/ingress/decode-runtime-input.ts +7 -0
  169. package/src/reducer/ingress/decode-session-state.ts +9 -0
  170. package/src/reducer/ingress/encode-session-state.ts +6 -0
  171. package/src/reducer/ingress/input-codec.ts +18 -0
  172. package/src/reducer/ingress/phase-schemas.ts +62 -0
  173. package/src/reducer/ingress/raw-types.ts +107 -0
  174. package/src/reducer/ingress/runtime-codec.ts +14 -0
  175. package/src/reducer/ingress/runtime-payload.ts +13 -0
  176. package/src/reducer/ingress/session-codec.ts +392 -0
  177. package/src/reducer/ingress/types.ts +6 -0
  178. package/src/reducer/inputs/boardInput.ts +217 -0
  179. package/src/reducer/inputs/boardTarget.ts +190 -0
  180. package/src/reducer/inputs/cardInput.ts +86 -0
  181. package/src/reducer/inputs/cardTarget.ts +101 -0
  182. package/src/reducer/inputs/choiceTarget.ts +104 -0
  183. package/src/reducer/inputs/defineInputs.ts +71 -0
  184. package/src/reducer/inputs/formInput.ts +809 -0
  185. package/src/reducer/inputs/many.ts +120 -0
  186. package/src/reducer/inputs/promptInput.ts +87 -0
  187. package/src/reducer/inputs/rngInput.ts +58 -0
  188. package/src/reducer/inputs/targetRule.ts +123 -0
  189. package/src/reducer/inputs.ts +41 -0
  190. package/src/reducer/model/definition.ts +1072 -0
  191. package/src/reducer/model/extract.ts +745 -0
  192. package/src/reducer/model/manifest.ts +570 -0
  193. package/src/reducer/model/queries.ts +641 -0
  194. package/src/reducer/model/runtime.ts +264 -0
  195. package/src/reducer/model/spec.ts +1386 -0
  196. package/src/reducer/model/table.ts +260 -0
  197. package/src/reducer/model.ts +7 -0
  198. package/src/reducer/ops.ts +1034 -0
  199. package/src/reducer/parse-utils.ts +28 -0
  200. package/src/reducer/per-player.ts +422 -0
  201. package/src/reducer/rng.ts +69 -0
  202. package/src/reducer/schema-helpers.ts +185 -0
  203. package/src/reducer/setup-bootstrap-helpers.ts +171 -0
  204. package/src/reducer/setup-bootstrap.ts +481 -0
  205. package/src/reducer/table-ops.ts +2671 -0
  206. package/src/reducer/table-queries.ts +372 -0
  207. package/src/reducer/transaction.ts +120 -0
  208. package/src/reducer.ts +314 -0
  209. package/src/runtime/primitives.ts +1 -0
  210. package/src/runtime/types/runtime-api.ts +1 -0
  211. package/src/runtime/workspace-contract.ts +32 -0
  212. package/src/runtime-internal/components/InteractionForm.tsx +1309 -0
  213. package/src/runtime-internal/components/PluginRuntime.tsx +103 -0
  214. package/src/runtime-internal/components/board/target-layer.ts +70 -0
  215. package/src/runtime-internal/context/ClientParamSchemaContext.tsx +44 -0
  216. package/src/runtime-internal/context/InteractionDraftContext.tsx +279 -0
  217. package/src/runtime-internal/context/PluginSessionContext.tsx +47 -0
  218. package/src/runtime-internal/context/PluginStateContext.tsx +262 -0
  219. package/src/runtime-internal/context/RuntimeContext.tsx +96 -0
  220. package/src/runtime-internal/defaults/components.tsx +409 -0
  221. package/src/runtime-internal/defaults/index.ts +11 -0
  222. package/src/runtime-internal/errors/ValidationError.ts +29 -0
  223. package/src/runtime-internal/hooks/useActivePlayers.ts +33 -0
  224. package/src/runtime-internal/hooks/useBoardInteractions.ts +665 -0
  225. package/src/runtime-internal/hooks/useGameSelector.ts +105 -0
  226. package/src/runtime-internal/hooks/useGameView.ts +9 -0
  227. package/src/runtime-internal/hooks/useInteractionByKey.ts +354 -0
  228. package/src/runtime-internal/hooks/useInteractionHandle.ts +438 -0
  229. package/src/runtime-internal/hooks/useIsMyTurn.ts +20 -0
  230. package/src/runtime-internal/hooks/useLobby.ts +76 -0
  231. package/src/runtime-internal/hooks/useMe.ts +48 -0
  232. package/src/runtime-internal/hooks/usePlayerInfo.ts +28 -0
  233. package/src/runtime-internal/hooks/usePlayerTurnOrder.ts +23 -0
  234. package/src/runtime-internal/hooks/usePluginRuntime.ts +147 -0
  235. package/src/runtime-internal/hooks/useSeatInbox.ts +61 -0
  236. package/src/runtime-internal/hooks/useSimultaneousPhase.ts +10 -0
  237. package/src/runtime-internal/index.ts +42 -0
  238. package/src/runtime-internal/internal.ts +43 -0
  239. package/src/runtime-internal/plugin-styles.css +250 -0
  240. package/src/runtime-internal/primitives/board.tsx +459 -0
  241. package/src/runtime-internal/primitives/dialog-lifecycle.ts +58 -0
  242. package/src/runtime-internal/primitives/dice.tsx +79 -0
  243. package/src/runtime-internal/primitives/game-ui-provider.tsx +35 -0
  244. package/src/runtime-internal/primitives/game.tsx +387 -0
  245. package/src/runtime-internal/primitives/hand-intent-adapter.ts +147 -0
  246. package/src/runtime-internal/primitives/hand-surface.tsx +594 -0
  247. package/src/runtime-internal/primitives/index.ts +196 -0
  248. package/src/runtime-internal/primitives/interaction-form-binding.tsx +56 -0
  249. package/src/runtime-internal/primitives/interaction-submit.ts +90 -0
  250. package/src/runtime-internal/primitives/interaction.tsx +987 -0
  251. package/src/runtime-internal/primitives/phase.tsx +43 -0
  252. package/src/runtime-internal/primitives/player-roster.tsx +302 -0
  253. package/src/runtime-internal/primitives/primitive-props.tsx +101 -0
  254. package/src/runtime-internal/primitives/prompt.tsx +255 -0
  255. package/src/runtime-internal/primitives/ui.tsx +60 -0
  256. package/src/runtime-internal/primitives/zone.tsx +791 -0
  257. package/src/runtime-internal/reducer.ts +30 -0
  258. package/src/runtime-internal/runtime/createPluginRuntimeAPI.ts +605 -0
  259. package/src/runtime-internal/types/plugin-state.ts +508 -0
  260. package/src/runtime-internal/types/reducer-state.ts +24 -0
  261. package/src/runtime-internal/types/runtime-api.ts +114 -0
  262. package/src/runtime-internal/ui-contract.ts +519 -0
  263. package/src/runtime-internal/utils/card-intent-adapter.ts +546 -0
  264. package/src/runtime-internal/utils/interaction-inputs.ts +492 -0
  265. package/src/runtime-internal/utils/interaction-labels.ts +23 -0
  266. package/src/runtime-internal/utils/interaction-router.ts +273 -0
  267. package/src/runtime-internal/utils/interaction-status.ts +74 -0
  268. package/src/runtime-internal/workspace-contract.ts +1170 -0
  269. package/src/runtime.ts +34 -0
  270. package/src/testing/create-expect-api.ts +352 -0
  271. package/src/testing/create-test-runtime.ts +381 -0
  272. package/src/testing/definitions.ts +127 -0
  273. package/src/testing/index.ts +3 -0
  274. package/src/testing.ts +1 -0
  275. package/src/type-stubs/manifest-contract.d.ts +42 -0
  276. package/src/type-stubs/manifest-contract.js +72 -0
  277. package/src/type-stubs/ui-contract.d.ts +5 -0
  278. package/src/type-stubs/ui-contract.js +1 -0
  279. package/src/types/authoring-card-properties.type-test.ts +266 -0
  280. package/src/types/authoring.ts +1282 -0
  281. package/src/types/cards.ts +19 -0
  282. package/src/types/contracts.ts +1550 -0
  283. package/src/types/generated-helpers.ts +35 -0
  284. package/src/types/index.ts +147 -0
  285. package/src/types/slots.ts +11 -0
  286. package/src/types.ts +1 -0
  287. package/src/ui/components/ActionButton.tsx +97 -0
  288. package/src/ui/components/ActionPanel.tsx +315 -0
  289. package/src/ui/components/Card.tsx +378 -0
  290. package/src/ui/components/CardDragSurface.tsx +1076 -0
  291. package/src/ui/components/ChromeSuppressionContext.tsx +70 -0
  292. package/src/ui/components/CostDisplay.tsx +145 -0
  293. package/src/ui/components/DiceRoller.tsx +581 -0
  294. package/src/ui/components/Drawer.tsx +180 -0
  295. package/src/ui/components/ErrorBoundary.tsx +275 -0
  296. package/src/ui/components/GameEndDisplay.tsx +398 -0
  297. package/src/ui/components/GameSkeleton.tsx +260 -0
  298. package/src/ui/components/Hand.tsx +468 -0
  299. package/src/ui/components/HandDock.tsx +299 -0
  300. package/src/ui/components/HandView.tsx +441 -0
  301. package/src/ui/components/MobileHandTray.tsx +381 -0
  302. package/src/ui/components/MoreActions.tsx +143 -0
  303. package/src/ui/components/PhaseIndicator.tsx +341 -0
  304. package/src/ui/components/PlayArea.tsx +146 -0
  305. package/src/ui/components/PrimaryActionButton.tsx +336 -0
  306. package/src/ui/components/PrimaryButton.tsx +45 -0
  307. package/src/ui/components/ResourceCounter.tsx +270 -0
  308. package/src/ui/components/StagingZone.tsx +134 -0
  309. package/src/ui/components/ThemedButton.tsx +113 -0
  310. package/src/ui/components/Toast.tsx +264 -0
  311. package/src/ui/components/board/HexGrid.tsx +1294 -0
  312. package/src/ui/components/board/NetworkGraph.tsx +476 -0
  313. package/src/ui/components/board/SlotSystem.tsx +388 -0
  314. package/src/ui/components/board/SquareGrid.tsx +1165 -0
  315. package/src/ui/components/board/TrackBoard.tsx +496 -0
  316. package/src/ui/components/board/ZoneMap.tsx +448 -0
  317. package/src/ui/components/board/hex-board-view.ts +123 -0
  318. package/src/ui/components/board/index.ts +142 -0
  319. package/src/ui/components/board/interaction-accessibility.ts +21 -0
  320. package/src/ui/components/board/target-layer.ts +66 -0
  321. package/src/ui/components/card-render-content.type-test.ts +27 -0
  322. package/src/ui/components/hand-layout-math.ts +163 -0
  323. package/src/ui/components/hand-pointer-engine.ts +413 -0
  324. package/src/ui/components/index.ts +245 -0
  325. package/src/ui/components.ts +1 -0
  326. package/src/ui/defaults/components.tsx +106 -0
  327. package/src/ui/defaults/index.ts +8 -0
  328. package/src/ui/defaults.ts +1 -0
  329. package/src/ui/errors/ValidationError.ts +29 -0
  330. package/src/ui/helpers/cards.ts +19 -0
  331. package/src/ui/helpers/track-board.ts +211 -0
  332. package/src/ui/hooks/useBoardTopology.ts +316 -0
  333. package/src/ui/hooks/useCards.ts +10 -0
  334. package/src/ui/hooks/useHandCardPointer.ts +381 -0
  335. package/src/ui/hooks/useHandLayout.ts +378 -0
  336. package/src/ui/hooks/useHandPresentation.ts +121 -0
  337. package/src/ui/hooks/useHexBoard.ts +74 -0
  338. package/src/ui/hooks/useHexGrid.ts +185 -0
  339. package/src/ui/hooks/useIsMobile.ts +35 -0
  340. package/src/ui/hooks/usePanZoom.ts +278 -0
  341. package/src/ui/hooks/useSquareBoard.ts +124 -0
  342. package/src/ui/hooks/useSquareGrid.ts +328 -0
  343. package/src/ui/index.ts +98 -0
  344. package/src/ui/internal/ui/alert.tsx +51 -0
  345. package/src/ui/internal/ui/button.tsx +58 -0
  346. package/src/ui/internal/ui/dialog.tsx +134 -0
  347. package/src/ui/internal/ui/input.tsx +21 -0
  348. package/src/ui/internal/ui/label.tsx +21 -0
  349. package/src/ui/internal/ui/select.tsx +129 -0
  350. package/src/ui/internal/ui/tooltip.tsx +54 -0
  351. package/src/ui/internal/ui/utils.ts +5 -0
  352. package/src/ui/plugin-styles.css +250 -0
  353. package/src/ui/primitives/dialog-lifecycle.ts +58 -0
  354. package/src/ui/primitives/dice.tsx +79 -0
  355. package/src/ui/primitives/primitive-props.tsx +101 -0
  356. package/src/ui/theme/ThemeProvider.tsx +252 -0
  357. package/src/ui/theme/board.ts +61 -0
  358. package/src/ui/theme/css-vars.ts +105 -0
  359. package/src/ui/theme/derive.ts +240 -0
  360. package/src/ui/theme/index.ts +61 -0
  361. package/src/ui/theme/presets/arcade.ts +261 -0
  362. package/src/ui/theme/presets/studio.ts +261 -0
  363. package/src/ui/theme/presets/tabletop.ts +266 -0
  364. package/src/ui/theme/tokens.ts +392 -0
  365. package/src/ui/types/hex-color.ts +20 -0
  366. package/src/ui/types/player-state.ts +463 -0
  367. package/src/ui/types/tiled-board.ts +785 -0
  368. package/src/ui/types/visual-state.ts +137 -0
  369. package/src/ui.ts +1 -0
@@ -0,0 +1,43 @@
1
+ import type { ReactElement, ReactNode } from "react";
2
+ import { usePluginState } from "../context/PluginStateContext.js";
3
+ import type { PhaseKey } from "../ui-contract.js";
4
+
5
+ export type PhaseRouteMap<Phase extends string = PhaseKey> = {
6
+ readonly [Key in Phase]: () => ReactNode;
7
+ };
8
+
9
+ export type PhaseFallback = ReactNode | ((phase: string | null) => ReactNode);
10
+
11
+ export interface PhaseSwitchProps<Phase extends string = PhaseKey> {
12
+ routes: PhaseRouteMap<Phase>;
13
+ fallback?: PhaseFallback;
14
+ }
15
+
16
+ function hasRoute<Phase extends string>(
17
+ routes: PhaseRouteMap<Phase>,
18
+ phase: string,
19
+ ): phase is Phase {
20
+ return Object.prototype.hasOwnProperty.call(routes, phase);
21
+ }
22
+
23
+ function renderFallback(
24
+ fallback: PhaseFallback | undefined,
25
+ phase: string | null,
26
+ ): ReactNode {
27
+ return typeof fallback === "function" ? fallback(phase) : (fallback ?? null);
28
+ }
29
+
30
+ export function PhaseSwitch<Phase extends string = PhaseKey>({
31
+ routes,
32
+ fallback,
33
+ }: PhaseSwitchProps<Phase>): ReactElement | null {
34
+ const phase = usePluginState((state) => state.gameplay.currentPhase);
35
+ if (phase && hasRoute(routes, phase)) {
36
+ return <>{routes[phase]()}</>;
37
+ }
38
+ return <>{renderFallback(fallback, phase)}</>;
39
+ }
40
+
41
+ export const Phase = {
42
+ Switch: PhaseSwitch,
43
+ };
@@ -0,0 +1,302 @@
1
+ import {
2
+ createContext,
3
+ Fragment,
4
+ useContext,
5
+ useMemo,
6
+ type ButtonHTMLAttributes,
7
+ type HTMLAttributes,
8
+ type ReactElement,
9
+ type ReactNode,
10
+ } from "react";
11
+ import type { PlayerId } from "@dreamboard/manifest-contract";
12
+ import { useActivePlayers } from "../hooks/useActivePlayers.js";
13
+ import { usePlayerInfo } from "../hooks/usePlayerInfo.js";
14
+ import { usePlayerTurnOrder } from "../hooks/usePlayerTurnOrder.js";
15
+ import { usePluginActions } from "../context/PluginStateContext.js";
16
+ import { usePluginSession } from "../context/PluginSessionContext.js";
17
+ import {
18
+ composeEventHandlers,
19
+ renderPrimitive,
20
+ type PrimitiveCommonProps,
21
+ } from "./primitive-props.js";
22
+ import type { HexColor } from "../../ui.js";
23
+
24
+ export interface PlayerRosterBadge {
25
+ key: string;
26
+ label?: ReactNode;
27
+ icon?: ReactNode;
28
+ tooltip?: string;
29
+ }
30
+
31
+ export interface PlayerRosterEntry {
32
+ playerId: PlayerId;
33
+ name: string;
34
+ color?: HexColor;
35
+ index: number;
36
+ isActive: boolean;
37
+ isCurrentPlayer: boolean;
38
+ isControllable: boolean;
39
+ canSwitchToPlayer: boolean;
40
+ score?: number;
41
+ scoreLabel?: string;
42
+ badges: readonly PlayerRosterBadge[];
43
+ metadata?: Record<string, unknown>;
44
+ }
45
+
46
+ export interface PlayerRosterRootProps {
47
+ children: ReactNode;
48
+ order?: "turn" | "self-first";
49
+ include?: "all" | "self" | "opponents";
50
+ score?: (playerId: PlayerId) => number | undefined;
51
+ scoreLabel?: string | ((playerId: PlayerId) => string | undefined);
52
+ badges?: (
53
+ playerId: PlayerId,
54
+ ) => ReadonlyArray<PlayerRosterBadge | null | false | undefined>;
55
+ metadata?: (playerId: PlayerId) => Record<string, unknown> | undefined;
56
+ }
57
+
58
+ interface PlayerRosterContextValue {
59
+ players: readonly PlayerRosterEntry[];
60
+ }
61
+
62
+ const PlayerRosterContext = createContext<PlayerRosterContextValue | null>(
63
+ null,
64
+ );
65
+
66
+ function usePlayerRosterContext(): PlayerRosterContextValue {
67
+ const value = useContext(PlayerRosterContext);
68
+ if (!value) {
69
+ throw new Error(
70
+ "PlayerRoster primitives must be rendered inside <PlayerRoster.Root>.",
71
+ );
72
+ }
73
+ return value;
74
+ }
75
+
76
+ function projectBadges(
77
+ badges: PlayerRosterRootProps["badges"],
78
+ playerId: PlayerId,
79
+ ): readonly PlayerRosterBadge[] {
80
+ return (badges?.(playerId) ?? []).filter(
81
+ (badge): badge is PlayerRosterBadge => Boolean(badge),
82
+ );
83
+ }
84
+
85
+ export function PlayerRosterRoot({
86
+ children,
87
+ order = "turn",
88
+ include = "all",
89
+ score,
90
+ scoreLabel,
91
+ badges,
92
+ metadata,
93
+ }: PlayerRosterRootProps) {
94
+ const playerInfo = usePlayerInfo();
95
+ const activePlayers = useActivePlayers();
96
+ const turnOrder = usePlayerTurnOrder();
97
+ const { controllingPlayerId, controllablePlayerIds } = usePluginSession();
98
+
99
+ const players = useMemo<readonly PlayerRosterEntry[]>(() => {
100
+ const orderedPlayerIds =
101
+ order === "self-first" && controllingPlayerId
102
+ ? [
103
+ ...turnOrder.filter((pid) => pid === controllingPlayerId),
104
+ ...turnOrder.filter((pid) => pid !== controllingPlayerId),
105
+ ]
106
+ : turnOrder;
107
+
108
+ return orderedPlayerIds
109
+ .map((playerId, index): PlayerRosterEntry => {
110
+ const player = playerInfo.get(playerId);
111
+ const isCurrentPlayer = playerId === controllingPlayerId;
112
+ const isControllable = controllablePlayerIds.includes(playerId);
113
+ const resolvedScoreLabel =
114
+ typeof scoreLabel === "function" ? scoreLabel(playerId) : scoreLabel;
115
+
116
+ return {
117
+ playerId,
118
+ name: player?.name ?? playerId,
119
+ color: player?.color,
120
+ index,
121
+ isActive: activePlayers.includes(playerId),
122
+ isCurrentPlayer,
123
+ isControllable,
124
+ canSwitchToPlayer:
125
+ controllablePlayerIds.length > 1 &&
126
+ isControllable &&
127
+ !isCurrentPlayer,
128
+ score: score?.(playerId),
129
+ scoreLabel: resolvedScoreLabel,
130
+ badges: projectBadges(badges, playerId),
131
+ metadata: metadata?.(playerId),
132
+ };
133
+ })
134
+ .filter((player) => {
135
+ if (include === "self") return player.isCurrentPlayer;
136
+ if (include === "opponents") return !player.isCurrentPlayer;
137
+ return true;
138
+ });
139
+ }, [
140
+ activePlayers,
141
+ badges,
142
+ controllablePlayerIds,
143
+ controllingPlayerId,
144
+ include,
145
+ metadata,
146
+ order,
147
+ playerInfo,
148
+ score,
149
+ scoreLabel,
150
+ turnOrder,
151
+ ]);
152
+
153
+ const value = useMemo<PlayerRosterContextValue>(
154
+ () => ({ players }),
155
+ [players],
156
+ );
157
+
158
+ return (
159
+ <PlayerRosterContext.Provider value={value}>
160
+ {children}
161
+ </PlayerRosterContext.Provider>
162
+ );
163
+ }
164
+
165
+ export type PlayerRosterListProps = Omit<PrimitiveCommonProps, "children"> &
166
+ Omit<HTMLAttributes<HTMLElement>, "children"> & {
167
+ children?: (player: PlayerRosterEntry) => ReactNode;
168
+ };
169
+
170
+ export function PlayerRosterList({
171
+ children,
172
+ ...props
173
+ }: PlayerRosterListProps) {
174
+ const { players } = usePlayerRosterContext();
175
+ return renderPrimitive("div", {
176
+ ...props,
177
+ "data-dreamboard-player-roster-list": "",
178
+ children: players.map((player) => (
179
+ <Fragment key={player.playerId}>
180
+ {children ? children(player) : <PlayerRosterName player={player} />}
181
+ </Fragment>
182
+ )),
183
+ });
184
+ }
185
+
186
+ export function PlayerRosterEmpty({ children }: { children?: ReactNode }) {
187
+ const { players } = usePlayerRosterContext();
188
+ if (players.length > 0) return null;
189
+ return <>{children}</>;
190
+ }
191
+
192
+ export type PlayerRosterSwitchButtonProps = Omit<
193
+ PrimitiveCommonProps,
194
+ "children"
195
+ > &
196
+ ButtonHTMLAttributes<HTMLButtonElement> & {
197
+ player: PlayerRosterEntry;
198
+ children?: ReactNode;
199
+ };
200
+
201
+ export function PlayerRosterSwitchButton({
202
+ player,
203
+ disabled,
204
+ onClick,
205
+ ...props
206
+ }: PlayerRosterSwitchButtonProps) {
207
+ const { switchPlayer } = usePluginActions();
208
+ const isDisabled = disabled === true || !player.canSwitchToPlayer;
209
+ return renderPrimitive("button", {
210
+ type: "button",
211
+ ...props,
212
+ disabled: isDisabled,
213
+ "aria-current": player.isCurrentPlayer ? "true" : undefined,
214
+ "aria-disabled": isDisabled,
215
+ "data-dreamboard-player-roster-switch": "",
216
+ "data-player-id": player.playerId,
217
+ "data-active": player.isActive || undefined,
218
+ "data-current": player.isCurrentPlayer || undefined,
219
+ "data-controllable": player.isControllable || undefined,
220
+ "data-switchable": player.canSwitchToPlayer || undefined,
221
+ "data-disabled": isDisabled || undefined,
222
+ onClick: composeEventHandlers(onClick, () => {
223
+ if (!isDisabled) switchPlayer(player.playerId);
224
+ }),
225
+ });
226
+ }
227
+
228
+ export type PlayerRosterPartProps = PrimitiveCommonProps &
229
+ HTMLAttributes<HTMLElement> & {
230
+ player: PlayerRosterEntry;
231
+ };
232
+
233
+ export interface PlayerRosterComponents {
234
+ Root(props: PlayerRosterRootProps): ReactElement | null;
235
+ List(props: PlayerRosterListProps): ReactElement;
236
+ Empty(props: { children?: ReactNode }): ReactElement | null;
237
+ SwitchButton(props: PlayerRosterSwitchButtonProps): ReactElement;
238
+ Name(props: PlayerRosterPartProps): ReactElement;
239
+ Score(props: PlayerRosterPartProps): ReactElement | null;
240
+ Badges(props: PlayerRosterPartProps): ReactElement | null;
241
+ }
242
+
243
+ export function PlayerRosterName({
244
+ player,
245
+ children,
246
+ ...props
247
+ }: PlayerRosterPartProps) {
248
+ return renderPrimitive("span", {
249
+ ...props,
250
+ "data-dreamboard-player-roster-name": "",
251
+ children: children ?? player.name,
252
+ });
253
+ }
254
+
255
+ export function PlayerRosterScore({
256
+ player,
257
+ children,
258
+ ...props
259
+ }: PlayerRosterPartProps) {
260
+ if (player.score === undefined && children === undefined) return null;
261
+ const label = player.scoreLabel ? ` ${player.scoreLabel}` : "";
262
+ return renderPrimitive("span", {
263
+ ...props,
264
+ "data-dreamboard-player-roster-score": "",
265
+ children: children ?? `${player.score}${label}`,
266
+ });
267
+ }
268
+
269
+ export function PlayerRosterBadges({
270
+ player,
271
+ children,
272
+ ...props
273
+ }: PlayerRosterPartProps) {
274
+ if (player.badges.length === 0 && children === undefined) return null;
275
+ return renderPrimitive("span", {
276
+ ...props,
277
+ "data-dreamboard-player-roster-badges": "",
278
+ children:
279
+ children ??
280
+ player.badges.map((badge) => (
281
+ <span
282
+ key={badge.key}
283
+ data-dreamboard-player-roster-badge=""
284
+ title={badge.tooltip}
285
+ aria-label={badge.tooltip}
286
+ >
287
+ {badge.icon}
288
+ {badge.label}
289
+ </span>
290
+ )),
291
+ });
292
+ }
293
+
294
+ export const PlayerRoster: PlayerRosterComponents = {
295
+ Root: PlayerRosterRoot,
296
+ List: PlayerRosterList,
297
+ Empty: PlayerRosterEmpty,
298
+ SwitchButton: PlayerRosterSwitchButton,
299
+ Name: PlayerRosterName,
300
+ Score: PlayerRosterScore,
301
+ Badges: PlayerRosterBadges,
302
+ };
@@ -0,0 +1,101 @@
1
+ import {
2
+ cloneElement,
3
+ isValidElement,
4
+ type AriaAttributes,
5
+ type CSSProperties,
6
+ type HTMLAttributes,
7
+ type JSX,
8
+ type ChangeEvent,
9
+ type MouseEvent,
10
+ type PointerEvent,
11
+ type ReactElement,
12
+ type ReactNode,
13
+ } from "react";
14
+
15
+ export type PrimitiveDataAttributes = Record<
16
+ `data-${string}`,
17
+ string | boolean | number | undefined
18
+ >;
19
+
20
+ export type PrimitiveCommonProps = {
21
+ asChild?: boolean;
22
+ children?: ReactNode;
23
+ className?: string;
24
+ style?: CSSProperties;
25
+ } & AriaAttributes &
26
+ PrimitiveDataAttributes;
27
+
28
+ type EventHandler<Event> = (event: Event) => void;
29
+
30
+ export function composeEventHandlers<
31
+ Event extends { defaultPrevented: boolean },
32
+ >(
33
+ authorHandler: EventHandler<Event> | undefined,
34
+ primitiveHandler: EventHandler<Event> | undefined,
35
+ ): EventHandler<Event> | undefined {
36
+ if (!authorHandler) return primitiveHandler;
37
+ if (!primitiveHandler) return authorHandler;
38
+ return (event) => {
39
+ authorHandler(event);
40
+ if (!event.defaultPrevented) {
41
+ primitiveHandler(event);
42
+ }
43
+ };
44
+ }
45
+
46
+ export function renderPrimitive<
47
+ ElementProps extends HTMLAttributes<HTMLElement>,
48
+ >(
49
+ tagName: keyof JSX.IntrinsicElements,
50
+ props: ElementProps & PrimitiveCommonProps,
51
+ ): ReactElement {
52
+ const { asChild, children, ...primitiveProps } = props;
53
+ if (asChild) {
54
+ if (!isValidElement(children)) {
55
+ throw new Error(
56
+ "asChild requires exactly one valid React element child.",
57
+ );
58
+ }
59
+ const element = children as ReactElement<HTMLAttributes<HTMLElement>>;
60
+ const childProps = element.props;
61
+ return cloneElement(element, {
62
+ ...primitiveProps,
63
+ ...childProps,
64
+ className: [primitiveProps.className, childProps.className]
65
+ .filter(Boolean)
66
+ .join(" "),
67
+ style: {
68
+ ...(primitiveProps.style ?? {}),
69
+ ...(childProps.style ?? {}),
70
+ },
71
+ onClick: composeEventHandlers(
72
+ childProps.onClick,
73
+ primitiveProps.onClick as EventHandler<MouseEvent<HTMLElement>>,
74
+ ),
75
+ onPointerDown: composeEventHandlers(
76
+ childProps.onPointerDown,
77
+ primitiveProps.onPointerDown as EventHandler<PointerEvent<HTMLElement>>,
78
+ ),
79
+ onPointerMove: composeEventHandlers(
80
+ childProps.onPointerMove,
81
+ primitiveProps.onPointerMove as EventHandler<PointerEvent<HTMLElement>>,
82
+ ),
83
+ onPointerUp: composeEventHandlers(
84
+ childProps.onPointerUp,
85
+ primitiveProps.onPointerUp as EventHandler<PointerEvent<HTMLElement>>,
86
+ ),
87
+ onPointerCancel: composeEventHandlers(
88
+ childProps.onPointerCancel,
89
+ primitiveProps.onPointerCancel as EventHandler<
90
+ PointerEvent<HTMLElement>
91
+ >,
92
+ ),
93
+ onChange: composeEventHandlers(
94
+ childProps.onChange,
95
+ primitiveProps.onChange as EventHandler<ChangeEvent<HTMLElement>>,
96
+ ),
97
+ });
98
+ }
99
+ const Tag = tagName as keyof JSX.IntrinsicElements;
100
+ return <Tag {...(primitiveProps as object)}>{children}</Tag>;
101
+ }
@@ -0,0 +1,255 @@
1
+ import {
2
+ Fragment,
3
+ createContext,
4
+ useContext,
5
+ useMemo,
6
+ type ButtonHTMLAttributes,
7
+ type ReactNode,
8
+ } from "react";
9
+ import { useSeatInbox } from "../hooks/useSeatInbox.js";
10
+ import type { PromptKey, PromptOptionKey } from "../ui-contract.js";
11
+ import type {
12
+ InteractionDescriptor,
13
+ InteractionContextOption,
14
+ } from "../types/plugin-state.js";
15
+ import { interactionInputKeys } from "../utils/interaction-inputs.js";
16
+ import { interactionLabel } from "../utils/interaction-labels.js";
17
+ import { isInteractionAvailable } from "../utils/interaction-status.js";
18
+ import {
19
+ InteractionDescription,
20
+ InteractionLabel,
21
+ InteractionRoot,
22
+ useInteractionPrimitiveContext,
23
+ type InteractionPartProps,
24
+ type InteractionRootProps,
25
+ } from "./interaction.js";
26
+ import {
27
+ composeEventHandlers,
28
+ renderPrimitive,
29
+ type PrimitiveCommonProps,
30
+ } from "./primitive-props.js";
31
+ import {
32
+ submitInteractionParams,
33
+ type InteractionSubmitCallbacks,
34
+ } from "./interaction-submit.js";
35
+ import {
36
+ useDialogLifecycle,
37
+ type DialogLifecycleState,
38
+ } from "./dialog-lifecycle.js";
39
+ import { useGameActionError } from "./game.js";
40
+
41
+ export type PromptRootProps<Prompt extends string = PromptKey> =
42
+ InteractionRootProps<Prompt>;
43
+
44
+ export function PromptRoot<Prompt extends string = PromptKey>(
45
+ props: PromptRootProps<Prompt>,
46
+ ) {
47
+ return <InteractionRoot {...props} />;
48
+ }
49
+
50
+ export function PromptTitle(props: InteractionPartProps) {
51
+ const { descriptor } = useInteractionPrimitiveContext();
52
+ const context =
53
+ descriptor?.kind === "prompt" ? descriptor.context : undefined;
54
+ return (
55
+ <InteractionLabel {...props}>
56
+ {props.children ??
57
+ context?.title ??
58
+ (descriptor ? interactionLabel(descriptor) : undefined)}
59
+ </InteractionLabel>
60
+ );
61
+ }
62
+
63
+ export function PromptMessage(props: InteractionPartProps) {
64
+ const { descriptor } = useInteractionPrimitiveContext();
65
+ const context =
66
+ descriptor?.kind === "prompt" ? descriptor.context : undefined;
67
+ const message =
68
+ props.children ??
69
+ (typeof context?.payload?.message === "string"
70
+ ? context.payload.message
71
+ : undefined);
72
+ if (!message) return null;
73
+ return <InteractionDescription {...props}>{message}</InteractionDescription>;
74
+ }
75
+
76
+ export type PromptOptionProps<Option extends string = PromptOptionKey> =
77
+ PrimitiveCommonProps &
78
+ ButtonHTMLAttributes<HTMLButtonElement> & {
79
+ value: Option;
80
+ disableWhenUnavailable?: boolean;
81
+ onSubmitError?: InteractionSubmitCallbacks["onSubmitError"];
82
+ onSubmitSuccess?: InteractionSubmitCallbacks["onSubmitSuccess"];
83
+ };
84
+
85
+ export function PromptOption<Option extends string = PromptOptionKey>({
86
+ value,
87
+ disabled,
88
+ disableWhenUnavailable = false,
89
+ onClick,
90
+ onSubmitError,
91
+ onSubmitSuccess,
92
+ children,
93
+ ...props
94
+ }: PromptOptionProps<Option>) {
95
+ const { descriptor, handle } = useInteractionPrimitiveContext();
96
+ const gameActionError = useGameActionError();
97
+ const context =
98
+ descriptor?.kind === "prompt" ? descriptor.context : undefined;
99
+ const option = context?.options?.find((candidate) => candidate.id === value);
100
+ const inputKey = descriptor ? interactionInputKeys(descriptor)[0] : undefined;
101
+ const choice = descriptor?.inputs.find(
102
+ (input) => input.key === inputKey,
103
+ )?.domain;
104
+ const optionChoice =
105
+ choice?.type === "choice"
106
+ ? choice.choices?.find((candidate) => candidate.value === value)
107
+ : undefined;
108
+ const isDisabled =
109
+ disabled ??
110
+ (!handle ||
111
+ !inputKey ||
112
+ handle.status !== "open" ||
113
+ optionChoice?.disabled === true ||
114
+ (disableWhenUnavailable && !isInteractionAvailable(descriptor)));
115
+ return renderPrimitive("button", {
116
+ type: "button",
117
+ ...props,
118
+ disabled: isDisabled,
119
+ "aria-disabled": isDisabled,
120
+ "data-dreamboard-prompt-option": "",
121
+ "data-option-value": value,
122
+ "data-disabled": isDisabled || undefined,
123
+ "data-available": isInteractionAvailable(descriptor),
124
+ "data-disabled-reason": optionChoice?.disabledReason,
125
+ title: props.title ?? optionChoice?.disabledReason,
126
+ onClick: composeEventHandlers(onClick, () => {
127
+ if (!handle || !inputKey || isDisabled) return;
128
+ void submitInteractionParams(
129
+ handle,
130
+ { [inputKey]: value },
131
+ {
132
+ onSubmitSuccess,
133
+ onSubmitError: onSubmitError ?? gameActionError ?? undefined,
134
+ },
135
+ { unhandledError: "log" },
136
+ );
137
+ }),
138
+ children: children ?? option?.label ?? value,
139
+ });
140
+ }
141
+
142
+ export interface PromptOptionRenderItem {
143
+ id: string;
144
+ label?: string;
145
+ }
146
+
147
+ export interface PromptOptionsProps {
148
+ children: (option: PromptOptionRenderItem) => ReactNode;
149
+ }
150
+
151
+ export function PromptOptions({ children }: PromptOptionsProps) {
152
+ const { descriptor } = useInteractionPrimitiveContext();
153
+ const options: readonly InteractionContextOption[] =
154
+ descriptor?.kind === "prompt" ? (descriptor.context.options ?? []) : [];
155
+ return (
156
+ <>
157
+ {options.map((option) => (
158
+ <Fragment key={option.id}>{children(option)}</Fragment>
159
+ ))}
160
+ </>
161
+ );
162
+ }
163
+
164
+ export type PromptDialogState = DialogLifecycleState;
165
+
166
+ export interface PromptDialogRenderState<Prompt extends string = PromptKey> {
167
+ prompt: Prompt;
168
+ state: PromptDialogState;
169
+ open: boolean;
170
+ minimized: boolean;
171
+ dismissed: boolean;
172
+ setOpen: (open: boolean) => void;
173
+ restore: () => void;
174
+ minimize: () => void;
175
+ dismiss: () => void;
176
+ }
177
+
178
+ export interface PromptDialogProps<Prompt extends string = PromptKey> {
179
+ prompt: Prompt;
180
+ defaultOpen?: boolean;
181
+ onStateChange?: (state: PromptDialogState) => void;
182
+ children: (state: PromptDialogRenderState<Prompt>) => ReactNode;
183
+ }
184
+
185
+ export function PromptDialog<Prompt extends string = PromptKey>({
186
+ prompt,
187
+ defaultOpen = true,
188
+ onStateChange,
189
+ children,
190
+ }: PromptDialogProps<Prompt>) {
191
+ const lifecycle = useDialogLifecycle({ defaultOpen, onStateChange });
192
+ const renderState = useMemo<PromptDialogRenderState<Prompt>>(
193
+ () => ({
194
+ prompt,
195
+ ...lifecycle,
196
+ }),
197
+ [lifecycle, prompt],
198
+ );
199
+ return <>{children(renderState)}</>;
200
+ }
201
+
202
+ interface PromptInboxContextValue {
203
+ prompts: readonly InteractionDescriptor[];
204
+ }
205
+
206
+ const PromptInboxContext = createContext<PromptInboxContextValue | null>(null);
207
+
208
+ function usePromptInboxContext(): PromptInboxContextValue {
209
+ const value = useContext(PromptInboxContext);
210
+ if (!value) {
211
+ throw new Error(
212
+ "PromptInbox primitives must be rendered inside <PromptInbox.Root>.",
213
+ );
214
+ }
215
+ return value;
216
+ }
217
+
218
+ export function PromptInboxRoot({ children }: { children: ReactNode }) {
219
+ const inbox = useSeatInbox();
220
+ return (
221
+ <PromptInboxContext.Provider value={{ prompts: inbox.prompts }}>
222
+ {children}
223
+ </PromptInboxContext.Provider>
224
+ );
225
+ }
226
+
227
+ export function PromptInboxEmpty({ children }: { children?: ReactNode }) {
228
+ const { prompts } = usePromptInboxContext();
229
+ if (prompts.length > 0) return null;
230
+ return <>{children}</>;
231
+ }
232
+
233
+ export interface PromptInboxItemsProps {
234
+ children: (prompt: InteractionDescriptor) => ReactNode;
235
+ }
236
+
237
+ export function PromptInboxItems({ children }: PromptInboxItemsProps) {
238
+ const { prompts } = usePromptInboxContext();
239
+ return <>{prompts.map((prompt) => children(prompt))}</>;
240
+ }
241
+
242
+ export const Prompt = {
243
+ Root: PromptRoot,
244
+ Title: PromptTitle,
245
+ Message: PromptMessage,
246
+ Option: PromptOption,
247
+ Options: PromptOptions,
248
+ Dialog: PromptDialog,
249
+ };
250
+
251
+ export const PromptInbox = {
252
+ Root: PromptInboxRoot,
253
+ Empty: PromptInboxEmpty,
254
+ Items: PromptInboxItems,
255
+ };