@dreamboard-games/sdk 0.2.1-alpha.0 → 0.3.0-alpha.1

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 (363) hide show
  1. package/dist/{HandView-ncJIVLhN.d.ts → HandView-PYDmehVD.d.ts} +1 -1
  2. package/dist/{ResourceCounter-CTREyF73.d.ts → ResourceCounter-BTXklCEZ.d.ts} +1 -1
  3. package/dist/{ThemeProvider-fy0_QzgO.d.ts → ThemeProvider-DvMl17Ny.d.ts} +1 -1
  4. package/dist/attributes-BeRyboMS.d.ts +279 -0
  5. package/dist/browser-interaction.d.ts +708 -0
  6. package/dist/browser-interaction.js +106 -0
  7. package/dist/{chunk-KAELH4KC.js → chunk-3RQEICD3.js} +2 -2
  8. package/dist/{chunk-TDSWKVZ4.js → chunk-ADYH6PVT.js} +2457 -1265
  9. package/dist/chunk-ADYH6PVT.js.map +1 -0
  10. package/dist/{chunk-YFY3RL52.js → chunk-P7VMTJ5D.js} +2 -2
  11. package/dist/{chunk-YFY3RL52.js.map → chunk-P7VMTJ5D.js.map} +1 -1
  12. package/dist/chunk-QLG6VEMW.js +1691 -0
  13. package/dist/chunk-QLG6VEMW.js.map +1 -0
  14. package/dist/{chunk-WYPQ3GG5.js → chunk-QZ6X4B5P.js} +1177 -1106
  15. package/dist/chunk-QZ6X4B5P.js.map +1 -0
  16. package/dist/{chunk-GKKBPPSW.js → chunk-TXXLS3OI.js} +405 -309
  17. package/dist/chunk-TXXLS3OI.js.map +1 -0
  18. package/dist/{chunk-FDNZTDD6.js → chunk-W6SGFWXH.js} +48 -44
  19. package/dist/chunk-W6SGFWXH.js.map +1 -0
  20. package/dist/{chunk-MKXPVOUT.js → chunk-Y2AFYBMB.js} +48 -4
  21. package/dist/chunk-Y2AFYBMB.js.map +1 -0
  22. package/dist/{index-BwqPQtBu.d.ts → codegen.d.ts} +57 -565
  23. package/dist/{infrastructure/workspace-codegen.js → codegen.js} +3 -3
  24. package/dist/{components-D5ZRE2Hl.d.ts → components-DaIqi9QM.d.ts} +48 -37
  25. package/dist/{hex-board-view-D_07hO6O.d.ts → hex-board-view-UCUjMALd.d.ts} +3 -2
  26. package/dist/{infrastructure/reducer-bundle-abi.d.ts → index.d-BGqVifr_.d.ts} +289 -10
  27. package/dist/index.js +1 -1
  28. package/dist/package-set.d.ts +2 -2
  29. package/dist/package-set.js +1 -1
  30. package/dist/primitive-props-BNHDkgd7.d.ts +16 -0
  31. package/dist/reducer-contract.d.ts +3 -0
  32. package/dist/{infrastructure/reducer-bundle-abi.js → reducer-contract.js} +4 -4
  33. package/dist/reducer.d.ts +185 -179
  34. package/dist/reducer.js +1637 -1353
  35. package/dist/reducer.js.map +1 -1
  36. package/dist/runtime/primitives.d.ts +10 -9
  37. package/dist/runtime/primitives.js +8 -7
  38. package/dist/runtime/runtime-api.d.ts +2 -0
  39. package/dist/runtime/runtime-api.js +1 -0
  40. package/dist/runtime/workspace-contract.d.ts +63 -17
  41. package/dist/runtime/workspace-contract.js +5 -5
  42. package/dist/{runtime-api-DWxvTr-O.d.ts → runtime-api-tGL3ArsB.d.ts} +109 -4
  43. package/dist/runtime.d.ts +12 -57
  44. package/dist/runtime.js +487 -7
  45. package/dist/runtime.js.map +1 -1
  46. package/dist/testing.d.ts +4 -4
  47. package/dist/testing.js.map +1 -1
  48. package/dist/types.d.ts +1531 -85
  49. package/dist/types.js +1 -3
  50. package/dist/types.js.map +1 -1
  51. package/dist/ui/components.d.ts +7 -8
  52. package/dist/ui/components.js +1 -1
  53. package/dist/ui/defaults.d.ts +1 -1
  54. package/dist/ui/{types/player-state.d.ts → player-state.d.ts} +2 -2
  55. package/dist/{ui-contract-iQfTtUSL.d.ts → ui-contract-SctM4ibF.d.ts} +157 -150
  56. package/dist/ui.d.ts +10 -11
  57. package/dist/ui.js +2 -2
  58. package/package.json +35 -74
  59. package/dist/bundle-CDd5FKeD.d.ts +0 -283
  60. package/dist/cards-Sl3b40Mv.d.ts +0 -13
  61. package/dist/chunk-7YAHLYBR.js +0 -481
  62. package/dist/chunk-7YAHLYBR.js.map +0 -1
  63. package/dist/chunk-FDNZTDD6.js.map +0 -1
  64. package/dist/chunk-GKKBPPSW.js.map +0 -1
  65. package/dist/chunk-I46YJSOD.js +0 -1
  66. package/dist/chunk-MKXPVOUT.js.map +0 -1
  67. package/dist/chunk-T52J5RMF.js +0 -1
  68. package/dist/chunk-TDSWKVZ4.js.map +0 -1
  69. package/dist/chunk-U5C6BONG.js +0 -34
  70. package/dist/chunk-U5C6BONG.js.map +0 -1
  71. package/dist/chunk-WYPQ3GG5.js.map +0 -1
  72. package/dist/generated/runtime/primitives.d.ts +0 -12
  73. package/dist/generated/runtime/primitives.js +0 -180
  74. package/dist/generated/runtime/primitives.js.map +0 -1
  75. package/dist/generated/runtime-api.d.ts +0 -3
  76. package/dist/generated/runtime-api.js +0 -2
  77. package/dist/generated/runtime.d.ts +0 -14
  78. package/dist/generated/runtime.js +0 -18
  79. package/dist/generated/runtime.js.map +0 -1
  80. package/dist/generated/workspace-contract.d.ts +0 -14
  81. package/dist/generated/workspace-contract.js +0 -14
  82. package/dist/generated/workspace-contract.js.map +0 -1
  83. package/dist/infrastructure/reducer-bundle-abi.js.map +0 -1
  84. package/dist/infrastructure/workspace-codegen.d.ts +0 -53
  85. package/dist/infrastructure/workspace-codegen.js.map +0 -1
  86. package/dist/manifest-contract-BNHVGFtU.d.ts +0 -9
  87. package/dist/primitive-props-DpKs-GCr.d.ts +0 -11
  88. package/dist/runtime/types/runtime-api.d.ts +0 -1
  89. package/dist/runtime/types/runtime-api.js +0 -2
  90. package/dist/runtime-api-3dshj6kK.d.ts +0 -101
  91. package/dist/slots-1GPGihk8.d.ts +0 -8
  92. package/src/generated/reducer-contract/builders.ts +0 -90
  93. package/src/generated/reducer-contract/version.ts +0 -9
  94. package/src/generated/reducer-contract/wire.ts +0 -100
  95. package/src/generated/reducer-contract/zod.ts +0 -103
  96. package/src/generated/runtime/primitives.ts +0 -2
  97. package/src/generated/runtime-api.ts +0 -5
  98. package/src/generated/runtime.ts +0 -35
  99. package/src/generated/workspace-contract.ts +0 -2
  100. package/src/index.ts +0 -7
  101. package/src/infrastructure/reducer-bundle-abi.ts +0 -8
  102. package/src/infrastructure/reducer-contract/bundle.ts +0 -37
  103. package/src/infrastructure/workspace-codegen/hex-geometry.ts +0 -69
  104. package/src/infrastructure/workspace-codegen/index.ts +0 -64
  105. package/src/infrastructure/workspace-codegen/manifest-contract.ts +0 -6632
  106. package/src/infrastructure/workspace-codegen/manifest-validation.ts +0 -795
  107. package/src/infrastructure/workspace-codegen/ownership.ts +0 -131
  108. package/src/infrastructure/workspace-codegen/preset-card-sets.ts +0 -169
  109. package/src/infrastructure/workspace-codegen/seeds.ts +0 -1705
  110. package/src/infrastructure/workspace-codegen.ts +0 -1
  111. package/src/package-set.ts +0 -19
  112. package/src/reducer/authoring/contract.ts +0 -157
  113. package/src/reducer/authoring/effect.ts +0 -224
  114. package/src/reducer/authoring/game.ts +0 -23
  115. package/src/reducer/authoring/interaction.ts +0 -98
  116. package/src/reducer/authoring/phase.ts +0 -300
  117. package/src/reducer/authoring/types.ts +0 -70
  118. package/src/reducer/authoring/validation.ts +0 -382
  119. package/src/reducer/authoring/view-stage.ts +0 -68
  120. package/src/reducer/authoring.ts +0 -29
  121. package/src/reducer/bundle/ingress-bundle.ts +0 -491
  122. package/src/reducer/bundle/trusted/engine-instruction-resolver.ts +0 -254
  123. package/src/reducer/bundle/trusted/flow-instruction-resolver.ts +0 -73
  124. package/src/reducer/bundle/trusted/instruction-runner.ts +0 -414
  125. package/src/reducer/bundle/trusted/interaction-authorization.ts +0 -137
  126. package/src/reducer/bundle/trusted/interaction-collectors.ts +0 -859
  127. package/src/reducer/bundle/trusted/interaction-decision.ts +0 -747
  128. package/src/reducer/bundle/trusted/interaction-resolver.ts +0 -95
  129. package/src/reducer/bundle/trusted/interaction-types.ts +0 -171
  130. package/src/reducer/bundle/trusted/lifecycle-runner.ts +0 -427
  131. package/src/reducer/bundle/trusted/projection-builder.ts +0 -356
  132. package/src/reducer/bundle/trusted/projection-context.ts +0 -39
  133. package/src/reducer/bundle/trusted/rng-sampler.ts +0 -150
  134. package/src/reducer/bundle/trusted/runtime-registry.ts +0 -120
  135. package/src/reducer/bundle/trusted/runtime-scope.ts +0 -336
  136. package/src/reducer/bundle/trusted/simultaneous-player.ts +0 -97
  137. package/src/reducer/bundle/trusted/stage-resolver.ts +0 -87
  138. package/src/reducer/bundle/trusted/static-projection.ts +0 -116
  139. package/src/reducer/bundle/trusted/trusted-runtime-args.ts +0 -97
  140. package/src/reducer/bundle/trusted/trusted-runtime-result.ts +0 -39
  141. package/src/reducer/bundle/trusted/trusted-setup-profiles.ts +0 -43
  142. package/src/reducer/bundle/trusted/trusted-state-codec.ts +0 -48
  143. package/src/reducer/bundle/trusted-bundle.ts +0 -97
  144. package/src/reducer/bundle/types.ts +0 -171
  145. package/src/reducer/bundle.ts +0 -2
  146. package/src/reducer/client-param-schemas.ts +0 -57
  147. package/src/reducer/compose.ts +0 -34
  148. package/src/reducer/core/runtime-input.ts +0 -30
  149. package/src/reducer/core/runtime-instruction.ts +0 -59
  150. package/src/reducer/core/types.ts +0 -62
  151. package/src/reducer/definition-index.ts +0 -277
  152. package/src/reducer/derived.ts +0 -106
  153. package/src/reducer/effects.ts +0 -92
  154. package/src/reducer/engine/runtime-instruction-engine.ts +0 -155
  155. package/src/reducer/ingress/decode-runtime-input.ts +0 -7
  156. package/src/reducer/ingress/decode-session-state.ts +0 -9
  157. package/src/reducer/ingress/encode-session-state.ts +0 -6
  158. package/src/reducer/ingress/input-codec.ts +0 -18
  159. package/src/reducer/ingress/phase-schemas.ts +0 -62
  160. package/src/reducer/ingress/raw-types.ts +0 -107
  161. package/src/reducer/ingress/runtime-codec.ts +0 -14
  162. package/src/reducer/ingress/runtime-payload.ts +0 -13
  163. package/src/reducer/ingress/session-codec.ts +0 -392
  164. package/src/reducer/ingress/types.ts +0 -6
  165. package/src/reducer/inputs/boardInput.ts +0 -217
  166. package/src/reducer/inputs/boardTarget.ts +0 -190
  167. package/src/reducer/inputs/cardInput.ts +0 -86
  168. package/src/reducer/inputs/cardTarget.ts +0 -101
  169. package/src/reducer/inputs/choiceTarget.ts +0 -104
  170. package/src/reducer/inputs/defineInputs.ts +0 -71
  171. package/src/reducer/inputs/formInput.ts +0 -809
  172. package/src/reducer/inputs/many.ts +0 -120
  173. package/src/reducer/inputs/promptInput.ts +0 -87
  174. package/src/reducer/inputs/rngInput.ts +0 -58
  175. package/src/reducer/inputs/targetRule.ts +0 -123
  176. package/src/reducer/inputs.ts +0 -41
  177. package/src/reducer/model/definition.ts +0 -1072
  178. package/src/reducer/model/extract.ts +0 -745
  179. package/src/reducer/model/manifest.ts +0 -570
  180. package/src/reducer/model/queries.ts +0 -641
  181. package/src/reducer/model/runtime.ts +0 -264
  182. package/src/reducer/model/spec.ts +0 -1386
  183. package/src/reducer/model/table.ts +0 -260
  184. package/src/reducer/model.ts +0 -7
  185. package/src/reducer/ops.ts +0 -1034
  186. package/src/reducer/parse-utils.ts +0 -28
  187. package/src/reducer/per-player.ts +0 -422
  188. package/src/reducer/rng.ts +0 -69
  189. package/src/reducer/schema-helpers.ts +0 -185
  190. package/src/reducer/setup-bootstrap-helpers.ts +0 -171
  191. package/src/reducer/setup-bootstrap.ts +0 -481
  192. package/src/reducer/table-ops.ts +0 -2671
  193. package/src/reducer/table-queries.ts +0 -372
  194. package/src/reducer/transaction.ts +0 -120
  195. package/src/reducer.ts +0 -314
  196. package/src/runtime/primitives.ts +0 -1
  197. package/src/runtime/types/runtime-api.ts +0 -1
  198. package/src/runtime/workspace-contract.ts +0 -32
  199. package/src/runtime-internal/components/InteractionForm.tsx +0 -1309
  200. package/src/runtime-internal/components/PluginRuntime.tsx +0 -103
  201. package/src/runtime-internal/components/board/target-layer.ts +0 -70
  202. package/src/runtime-internal/context/ClientParamSchemaContext.tsx +0 -44
  203. package/src/runtime-internal/context/InteractionDraftContext.tsx +0 -279
  204. package/src/runtime-internal/context/PluginSessionContext.tsx +0 -47
  205. package/src/runtime-internal/context/PluginStateContext.tsx +0 -262
  206. package/src/runtime-internal/context/RuntimeContext.tsx +0 -96
  207. package/src/runtime-internal/defaults/components.tsx +0 -409
  208. package/src/runtime-internal/defaults/index.ts +0 -11
  209. package/src/runtime-internal/errors/ValidationError.ts +0 -29
  210. package/src/runtime-internal/hooks/useActivePlayers.ts +0 -33
  211. package/src/runtime-internal/hooks/useBoardInteractions.ts +0 -665
  212. package/src/runtime-internal/hooks/useGameSelector.ts +0 -105
  213. package/src/runtime-internal/hooks/useGameView.ts +0 -9
  214. package/src/runtime-internal/hooks/useInteractionByKey.ts +0 -354
  215. package/src/runtime-internal/hooks/useInteractionHandle.ts +0 -438
  216. package/src/runtime-internal/hooks/useIsMyTurn.ts +0 -20
  217. package/src/runtime-internal/hooks/useLobby.ts +0 -76
  218. package/src/runtime-internal/hooks/useMe.ts +0 -48
  219. package/src/runtime-internal/hooks/usePlayerInfo.ts +0 -28
  220. package/src/runtime-internal/hooks/usePlayerTurnOrder.ts +0 -23
  221. package/src/runtime-internal/hooks/usePluginRuntime.ts +0 -147
  222. package/src/runtime-internal/hooks/useSeatInbox.ts +0 -61
  223. package/src/runtime-internal/hooks/useSimultaneousPhase.ts +0 -10
  224. package/src/runtime-internal/index.ts +0 -42
  225. package/src/runtime-internal/internal.ts +0 -43
  226. package/src/runtime-internal/plugin-styles.css +0 -250
  227. package/src/runtime-internal/primitives/board.tsx +0 -459
  228. package/src/runtime-internal/primitives/dialog-lifecycle.ts +0 -58
  229. package/src/runtime-internal/primitives/dice.tsx +0 -79
  230. package/src/runtime-internal/primitives/game-ui-provider.tsx +0 -35
  231. package/src/runtime-internal/primitives/game.tsx +0 -387
  232. package/src/runtime-internal/primitives/hand-intent-adapter.ts +0 -147
  233. package/src/runtime-internal/primitives/hand-surface.tsx +0 -594
  234. package/src/runtime-internal/primitives/index.ts +0 -196
  235. package/src/runtime-internal/primitives/interaction-form-binding.tsx +0 -56
  236. package/src/runtime-internal/primitives/interaction-submit.ts +0 -90
  237. package/src/runtime-internal/primitives/interaction.tsx +0 -987
  238. package/src/runtime-internal/primitives/phase.tsx +0 -43
  239. package/src/runtime-internal/primitives/player-roster.tsx +0 -302
  240. package/src/runtime-internal/primitives/primitive-props.tsx +0 -101
  241. package/src/runtime-internal/primitives/prompt.tsx +0 -255
  242. package/src/runtime-internal/primitives/ui.tsx +0 -60
  243. package/src/runtime-internal/primitives/zone.tsx +0 -791
  244. package/src/runtime-internal/reducer.ts +0 -30
  245. package/src/runtime-internal/runtime/createPluginRuntimeAPI.ts +0 -605
  246. package/src/runtime-internal/types/plugin-state.ts +0 -508
  247. package/src/runtime-internal/types/reducer-state.ts +0 -24
  248. package/src/runtime-internal/types/runtime-api.ts +0 -114
  249. package/src/runtime-internal/ui-contract.ts +0 -519
  250. package/src/runtime-internal/utils/card-intent-adapter.ts +0 -546
  251. package/src/runtime-internal/utils/interaction-inputs.ts +0 -492
  252. package/src/runtime-internal/utils/interaction-labels.ts +0 -23
  253. package/src/runtime-internal/utils/interaction-router.ts +0 -273
  254. package/src/runtime-internal/utils/interaction-status.ts +0 -74
  255. package/src/runtime-internal/workspace-contract.ts +0 -1170
  256. package/src/runtime.ts +0 -34
  257. package/src/testing/create-expect-api.ts +0 -352
  258. package/src/testing/create-test-runtime.ts +0 -381
  259. package/src/testing/definitions.ts +0 -127
  260. package/src/testing/index.ts +0 -3
  261. package/src/testing.ts +0 -1
  262. package/src/type-stubs/manifest-contract.d.ts +0 -42
  263. package/src/type-stubs/manifest-contract.js +0 -72
  264. package/src/type-stubs/ui-contract.d.ts +0 -5
  265. package/src/type-stubs/ui-contract.js +0 -1
  266. package/src/types/authoring-card-properties.type-test.ts +0 -266
  267. package/src/types/authoring.ts +0 -1282
  268. package/src/types/cards.ts +0 -19
  269. package/src/types/contracts.ts +0 -1550
  270. package/src/types/generated-helpers.ts +0 -35
  271. package/src/types/index.ts +0 -147
  272. package/src/types/slots.ts +0 -11
  273. package/src/types.ts +0 -1
  274. package/src/ui/components/ActionButton.tsx +0 -97
  275. package/src/ui/components/ActionPanel.tsx +0 -315
  276. package/src/ui/components/Card.tsx +0 -378
  277. package/src/ui/components/CardDragSurface.tsx +0 -1076
  278. package/src/ui/components/ChromeSuppressionContext.tsx +0 -70
  279. package/src/ui/components/CostDisplay.tsx +0 -145
  280. package/src/ui/components/DiceRoller.tsx +0 -581
  281. package/src/ui/components/Drawer.tsx +0 -180
  282. package/src/ui/components/ErrorBoundary.tsx +0 -275
  283. package/src/ui/components/GameEndDisplay.tsx +0 -398
  284. package/src/ui/components/GameSkeleton.tsx +0 -260
  285. package/src/ui/components/Hand.tsx +0 -468
  286. package/src/ui/components/HandDock.tsx +0 -299
  287. package/src/ui/components/HandView.tsx +0 -441
  288. package/src/ui/components/MobileHandTray.tsx +0 -381
  289. package/src/ui/components/MoreActions.tsx +0 -143
  290. package/src/ui/components/PhaseIndicator.tsx +0 -341
  291. package/src/ui/components/PlayArea.tsx +0 -146
  292. package/src/ui/components/PrimaryActionButton.tsx +0 -336
  293. package/src/ui/components/PrimaryButton.tsx +0 -45
  294. package/src/ui/components/ResourceCounter.tsx +0 -270
  295. package/src/ui/components/StagingZone.tsx +0 -134
  296. package/src/ui/components/ThemedButton.tsx +0 -113
  297. package/src/ui/components/Toast.tsx +0 -264
  298. package/src/ui/components/board/HexGrid.tsx +0 -1294
  299. package/src/ui/components/board/NetworkGraph.tsx +0 -476
  300. package/src/ui/components/board/SlotSystem.tsx +0 -388
  301. package/src/ui/components/board/SquareGrid.tsx +0 -1165
  302. package/src/ui/components/board/TrackBoard.tsx +0 -496
  303. package/src/ui/components/board/ZoneMap.tsx +0 -448
  304. package/src/ui/components/board/hex-board-view.ts +0 -123
  305. package/src/ui/components/board/index.ts +0 -142
  306. package/src/ui/components/board/interaction-accessibility.ts +0 -21
  307. package/src/ui/components/board/target-layer.ts +0 -66
  308. package/src/ui/components/card-render-content.type-test.ts +0 -27
  309. package/src/ui/components/hand-layout-math.ts +0 -163
  310. package/src/ui/components/hand-pointer-engine.ts +0 -413
  311. package/src/ui/components/index.ts +0 -245
  312. package/src/ui/components.ts +0 -1
  313. package/src/ui/defaults/components.tsx +0 -106
  314. package/src/ui/defaults/index.ts +0 -8
  315. package/src/ui/defaults.ts +0 -1
  316. package/src/ui/errors/ValidationError.ts +0 -29
  317. package/src/ui/helpers/cards.ts +0 -19
  318. package/src/ui/helpers/track-board.ts +0 -211
  319. package/src/ui/hooks/useBoardTopology.ts +0 -316
  320. package/src/ui/hooks/useCards.ts +0 -10
  321. package/src/ui/hooks/useHandCardPointer.ts +0 -381
  322. package/src/ui/hooks/useHandLayout.ts +0 -378
  323. package/src/ui/hooks/useHandPresentation.ts +0 -121
  324. package/src/ui/hooks/useHexBoard.ts +0 -74
  325. package/src/ui/hooks/useHexGrid.ts +0 -185
  326. package/src/ui/hooks/useIsMobile.ts +0 -35
  327. package/src/ui/hooks/usePanZoom.ts +0 -278
  328. package/src/ui/hooks/useSquareBoard.ts +0 -124
  329. package/src/ui/hooks/useSquareGrid.ts +0 -328
  330. package/src/ui/index.ts +0 -98
  331. package/src/ui/internal/ui/alert.tsx +0 -51
  332. package/src/ui/internal/ui/button.tsx +0 -58
  333. package/src/ui/internal/ui/dialog.tsx +0 -134
  334. package/src/ui/internal/ui/input.tsx +0 -21
  335. package/src/ui/internal/ui/label.tsx +0 -21
  336. package/src/ui/internal/ui/select.tsx +0 -129
  337. package/src/ui/internal/ui/tooltip.tsx +0 -54
  338. package/src/ui/internal/ui/utils.ts +0 -5
  339. package/src/ui/plugin-styles.css +0 -250
  340. package/src/ui/primitives/dialog-lifecycle.ts +0 -58
  341. package/src/ui/primitives/dice.tsx +0 -79
  342. package/src/ui/primitives/primitive-props.tsx +0 -101
  343. package/src/ui/theme/ThemeProvider.tsx +0 -252
  344. package/src/ui/theme/board.ts +0 -61
  345. package/src/ui/theme/css-vars.ts +0 -105
  346. package/src/ui/theme/derive.ts +0 -240
  347. package/src/ui/theme/index.ts +0 -61
  348. package/src/ui/theme/presets/arcade.ts +0 -261
  349. package/src/ui/theme/presets/studio.ts +0 -261
  350. package/src/ui/theme/presets/tabletop.ts +0 -266
  351. package/src/ui/theme/tokens.ts +0 -392
  352. package/src/ui/types/hex-color.ts +0 -20
  353. package/src/ui/types/player-state.ts +0 -463
  354. package/src/ui/types/tiled-board.ts +0 -785
  355. package/src/ui/types/visual-state.ts +0 -137
  356. package/src/ui.ts +0 -1
  357. /package/dist/{chunk-I46YJSOD.js.map → browser-interaction.js.map} +0 -0
  358. /package/dist/{chunk-KAELH4KC.js.map → chunk-3RQEICD3.js.map} +0 -0
  359. /package/dist/{chunk-T52J5RMF.js.map → codegen.js.map} +0 -0
  360. /package/dist/{generated/runtime-api.js.map → reducer-contract.js.map} +0 -0
  361. /package/dist/runtime/{types/runtime-api.js.map → runtime-api.js.map} +0 -0
  362. /package/dist/ui/{types/player-state.js → player-state.js} +0 -0
  363. /package/dist/ui/{types/player-state.js.map → player-state.js.map} +0 -0
@@ -17,9 +17,25 @@ import {
17
17
  useChromeSuppression,
18
18
  useTheme,
19
19
  useThemeCssVars
20
- } from "./chunk-WYPQ3GG5.js";
20
+ } from "./chunk-QZ6X4B5P.js";
21
+ import {
22
+ composeEventHandlers,
23
+ renderPrimitive
24
+ } from "./chunk-VDXOF4FW.js";
25
+ import {
26
+ BROWSER_INTERACTION_ATTRIBUTES,
27
+ DREAMBOARD_BROWSER_INTERACTION_PROTOCOL_VERSION,
28
+ GAMEPLAY_BROWSER_INTERACTION_SURFACE,
29
+ createGameplayActuatorAttributes,
30
+ createGameplayInteractionRootAttributes,
31
+ gameplayAdjustResourceEffect,
32
+ gameplayCommitEffect,
33
+ gameplayInvokeEffect,
34
+ gameplaySetCandidateEffect,
35
+ gameplaySetScalarEffect
36
+ } from "./chunk-QLG6VEMW.js";
21
37
 
22
- // src/runtime-internal/primitives/ui.tsx
38
+ // src/runtime/primitives/ui.tsx
23
39
  import { Fragment, jsx } from "react/jsx-runtime";
24
40
  function UIRoot({
25
41
  theme,
@@ -48,10 +64,10 @@ var UI = {
48
64
  Root: UIRoot
49
65
  };
50
66
 
51
- // src/runtime-internal/primitives/hand-intent-adapter.ts
67
+ // src/runtime/primitives/hand-intent-adapter.ts
52
68
  import { useCallback } from "react";
53
69
 
54
- // src/runtime-internal/context/InteractionDraftContext.tsx
70
+ // src/runtime/context/InteractionDraftContext.tsx
55
71
  import { createContext, useContext, useMemo } from "react";
56
72
  import { useStore } from "zustand";
57
73
  import { createStore } from "zustand/vanilla";
@@ -235,7 +251,7 @@ function useInteractionSubmitting(interactionId) {
235
251
  );
236
252
  }
237
253
 
238
- // src/runtime-internal/context/PluginSessionContext.tsx
254
+ // src/runtime/context/PluginSessionContext.tsx
239
255
  import { createContext as createContext2, useContext as useContext2 } from "react";
240
256
  var PluginSessionContext = createContext2(
241
257
  null
@@ -250,7 +266,7 @@ function usePluginSession() {
250
266
  return context;
251
267
  }
252
268
 
253
- // src/runtime-internal/context/PluginStateContext.tsx
269
+ // src/runtime/context/PluginStateContext.tsx
254
270
  import {
255
271
  createContext as createContext4,
256
272
  useContext as useContext4,
@@ -260,7 +276,7 @@ import {
260
276
  useSyncExternalStore
261
277
  } from "react";
262
278
 
263
- // src/runtime-internal/context/RuntimeContext.tsx
279
+ // src/runtime/context/RuntimeContext.tsx
264
280
  import { createContext as createContext3, useContext as useContext3, useState, useEffect } from "react";
265
281
  import { jsx as jsx3 } from "react/jsx-runtime";
266
282
  var RuntimeContext = createContext3(null);
@@ -293,9 +309,376 @@ function RuntimeProvider({
293
309
  return /* @__PURE__ */ jsx3(RuntimeContext.Provider, { value: runtime, children: /* @__PURE__ */ jsx3(PluginSessionContext.Provider, { value: sessionState, children }) });
294
310
  }
295
311
 
296
- // src/runtime-internal/context/PluginStateContext.tsx
312
+ // src/runtime/utils/semantic-projection-digest.ts
313
+ var AUTHORIZED_SEAT_PROJECTION_DIGEST_VERSION = "authorized-seat-projection@2";
314
+ function semanticProjectionDigestForState(state) {
315
+ const actorPlayerId = state.session.controllingPlayerId;
316
+ if (!actorPlayerId) {
317
+ return null;
318
+ }
319
+ const seatOrder = state.lobby?.seats.map((seat) => seat.playerId) ?? [];
320
+ if (!seatOrder.includes(actorPlayerId)) {
321
+ return null;
322
+ }
323
+ return hashJson(semanticSeatProjection(state, state.gameplay, seatOrder));
324
+ }
325
+ function semanticSeatProjection(state, gameplay, seatOrder) {
326
+ const playerToSeat = new Map(
327
+ seatOrder.map((playerId, index) => [playerId, index])
328
+ );
329
+ const actorPlayerId = state.session.controllingPlayerId;
330
+ const actorSeat = actorPlayerId ? playerToSeat.get(actorPlayerId) : void 0;
331
+ if (actorSeat === void 0) {
332
+ throw new Error(
333
+ `authorized projection player ${actorPlayerId ?? "__none__"} is not present in seat order`
334
+ );
335
+ }
336
+ return {
337
+ digestVersion: AUTHORIZED_SEAT_PROJECTION_DIGEST_VERSION,
338
+ actorSeat,
339
+ currentStage: gameplay.currentStage ?? null,
340
+ stageSeats: gameplay.activePlayers.map(
341
+ (playerId) => canonicalizeSeatReference(playerId, playerToSeat)
342
+ ),
343
+ view: canonicalizeSemanticProjectionValue(state.view, playerToSeat),
344
+ zones: canonicalizeSemanticProjectionValue(gameplay.zones ?? {}, playerToSeat),
345
+ availableInteractions: gameplay.availableInteractions.map(
346
+ (descriptor) => semanticInteractionDescriptor(descriptor, playerToSeat)
347
+ )
348
+ };
349
+ }
350
+ function semanticInteractionDescriptor(descriptor, playerToSeat) {
351
+ const inputs = descriptor.inputs.map(
352
+ (input) => semanticInteractionInput(input, playerToSeat)
353
+ );
354
+ const { defaults, defaultProvenance } = collectDefaults(descriptor.inputs);
355
+ return {
356
+ interactionKey: descriptor.interactionKey,
357
+ interactionId: descriptor.interactionId,
358
+ stableIdentity: canonicalizeSemanticProjectionValue(
359
+ `${descriptor.interactionKey}:${descriptor.interactionId}`,
360
+ playerToSeat
361
+ ),
362
+ kind: descriptor.kind,
363
+ surface: descriptor.zoneId ?? descriptor.zoneIds?.find((zoneId) => typeof zoneId === "string") ?? null,
364
+ commitMode: descriptor.commit.mode === "autoWhenReady" ? "autoWhenReady" : "manual",
365
+ status: descriptor.availability.status ?? null,
366
+ available: descriptor.availability.status === "available",
367
+ inputs,
368
+ defaults: canonicalizeSemanticProjectionValue(defaults, playerToSeat),
369
+ defaultProvenance
370
+ };
371
+ }
372
+ function semanticInteractionInput(input, playerToSeat) {
373
+ const domain = asRecord(input.domain);
374
+ const selection = asRecord(domain.selection);
375
+ return {
376
+ key: input.key,
377
+ kind: input.kind,
378
+ domain: canonicalizeSemanticProjectionValue(input.domain, playerToSeat),
379
+ defaultValue: input.defaultValue === void 0 ? null : canonicalizeSemanticProjectionValue(input.defaultValue, playerToSeat),
380
+ defaultProvenance: input.defaultValue === void 0 ? null : "input",
381
+ selectionMode: stringField(selection, "mode"),
382
+ min: numberField(domain),
383
+ max: numberField(domain, "max")
384
+ };
385
+ }
386
+ function collectDefaults(inputs) {
387
+ const defaults = {};
388
+ const defaultProvenance = {};
389
+ for (const input of inputs) {
390
+ if (input.defaultValue !== void 0) {
391
+ defaults[input.key] = toCanonicalJson(input.defaultValue);
392
+ defaultProvenance[input.key] = "input";
393
+ }
394
+ }
395
+ return { defaults, defaultProvenance };
396
+ }
397
+ function canonicalizeSemanticProjectionValue(value, playerToSeat) {
398
+ if (value === null || typeof value === "boolean" || typeof value === "number") {
399
+ return toCanonicalJson(value);
400
+ }
401
+ if (typeof value === "string") {
402
+ return canonicalizeSeatReference(value, playerToSeat);
403
+ }
404
+ if (Array.isArray(value)) {
405
+ return value.map(
406
+ (item) => canonicalizeSemanticProjectionValue(item, playerToSeat)
407
+ );
408
+ }
409
+ if (isRecord(value)) {
410
+ return Object.fromEntries(
411
+ Object.entries(value).filter(
412
+ ([key, item]) => item !== void 0 && !SEMANTIC_PROJECTION_TRANSPORT_FIELDS.has(key)
413
+ ).map(([key, item]) => [
414
+ canonicalizeObjectKey(key, playerToSeat),
415
+ canonicalizeSemanticProjectionProperty(key, item, playerToSeat)
416
+ ])
417
+ );
418
+ }
419
+ return null;
420
+ }
421
+ function canonicalizeSemanticProjectionProperty(key, value, playerToSeat) {
422
+ const canonicalValue = canonicalizeSemanticProjectionValue(value, playerToSeat);
423
+ if ((key === "eligibleTargets" || key === "dependentCases") && Array.isArray(canonicalValue)) {
424
+ return [...canonicalValue].sort(
425
+ (left, right) => compareJson(canonicalJson(left), canonicalJson(right))
426
+ );
427
+ }
428
+ return canonicalValue;
429
+ }
430
+ function canonicalizeSeatReference(value, playerToSeat) {
431
+ const seat = playerToSeat.get(value);
432
+ return seat === void 0 ? value : { $seat: seat };
433
+ }
434
+ function canonicalizeObjectKey(key, playerToSeat) {
435
+ const seat = playerToSeat.get(key);
436
+ return seat === void 0 ? key : `$seat:${seat}`;
437
+ }
438
+ var SEMANTIC_PROJECTION_TRANSPORT_FIELDS = /* @__PURE__ */ new Set([
439
+ "availableInteractionRefs",
440
+ "board",
441
+ "cursor",
442
+ "etag",
443
+ "hydratedAt",
444
+ "hydrationCursor",
445
+ "hydrationSequence",
446
+ "interactionRef",
447
+ "interactionRefs",
448
+ "lastEventId",
449
+ "receivedAt",
450
+ "sequence",
451
+ "serverTime",
452
+ "snapshotVersion",
453
+ "transportSequence",
454
+ "transportVersion",
455
+ "updatedAt"
456
+ ]);
457
+ function toCanonicalJson(value) {
458
+ if (value === null || typeof value === "boolean" || typeof value === "string") {
459
+ return value;
460
+ }
461
+ if (typeof value === "number") {
462
+ return value;
463
+ }
464
+ if (Array.isArray(value)) {
465
+ return value.map((item) => toCanonicalJson(item));
466
+ }
467
+ if (isRecord(value)) {
468
+ return Object.fromEntries(
469
+ Object.entries(value).filter(([, item]) => item !== void 0).map(([key, item]) => [key, toCanonicalJson(item)])
470
+ );
471
+ }
472
+ return null;
473
+ }
474
+ function hashJson(value) {
475
+ return `sha256:${sha256Hex(canonicalJson(value))}`;
476
+ }
477
+ function canonicalJson(value) {
478
+ return JSON.stringify(canonicalizeJson(value));
479
+ }
480
+ function canonicalizeJson(value) {
481
+ if (value === null || typeof value === "boolean" || typeof value === "string") {
482
+ return value;
483
+ }
484
+ if (typeof value === "number") {
485
+ if (!Number.isFinite(value)) {
486
+ throw new Error("canonical JSON contains a non-finite number");
487
+ }
488
+ return value;
489
+ }
490
+ if (Array.isArray(value)) {
491
+ return value.map((item) => canonicalizeJson(item));
492
+ }
493
+ return Object.fromEntries(
494
+ Object.entries(value).sort(([left], [right]) => compareJson(left, right)).map(([key, item]) => [key, canonicalizeJson(item)])
495
+ );
496
+ }
497
+ function compareJson(left, right) {
498
+ return left < right ? -1 : left > right ? 1 : 0;
499
+ }
500
+ function isRecord(value) {
501
+ return !!value && typeof value === "object" && !Array.isArray(value);
502
+ }
503
+ function asRecord(value) {
504
+ return isRecord(value) ? value : {};
505
+ }
506
+ function stringField(record, key) {
507
+ const value = record[key];
508
+ return typeof value === "string" && value.trim() ? value : null;
509
+ }
510
+ function numberField(record, key = "min") {
511
+ const value = record[key];
512
+ return typeof value === "number" && Number.isFinite(value) ? value : null;
513
+ }
514
+ var SHA256_K = [
515
+ 1116352408,
516
+ 1899447441,
517
+ 3049323471,
518
+ 3921009573,
519
+ 961987163,
520
+ 1508970993,
521
+ 2453635748,
522
+ 2870763221,
523
+ 3624381080,
524
+ 310598401,
525
+ 607225278,
526
+ 1426881987,
527
+ 1925078388,
528
+ 2162078206,
529
+ 2614888103,
530
+ 3248222580,
531
+ 3835390401,
532
+ 4022224774,
533
+ 264347078,
534
+ 604807628,
535
+ 770255983,
536
+ 1249150122,
537
+ 1555081692,
538
+ 1996064986,
539
+ 2554220882,
540
+ 2821834349,
541
+ 2952996808,
542
+ 3210313671,
543
+ 3336571891,
544
+ 3584528711,
545
+ 113926993,
546
+ 338241895,
547
+ 666307205,
548
+ 773529912,
549
+ 1294757372,
550
+ 1396182291,
551
+ 1695183700,
552
+ 1986661051,
553
+ 2177026350,
554
+ 2456956037,
555
+ 2730485921,
556
+ 2820302411,
557
+ 3259730800,
558
+ 3345764771,
559
+ 3516065817,
560
+ 3600352804,
561
+ 4094571909,
562
+ 275423344,
563
+ 430227734,
564
+ 506948616,
565
+ 659060556,
566
+ 883997877,
567
+ 958139571,
568
+ 1322822218,
569
+ 1537002063,
570
+ 1747873779,
571
+ 1955562222,
572
+ 2024104815,
573
+ 2227730452,
574
+ 2361852424,
575
+ 2428436474,
576
+ 2756734187,
577
+ 3204031479,
578
+ 3329325298
579
+ ];
580
+ function sha256Hex(input) {
581
+ const bytes = utf8Bytes(input);
582
+ const bitLength = bytes.length * 8;
583
+ bytes.push(128);
584
+ while (bytes.length % 64 !== 56) {
585
+ bytes.push(0);
586
+ }
587
+ for (let shift = 56; shift >= 0; shift -= 8) {
588
+ bytes.push(Math.floor(bitLength / 2 ** shift) & 255);
589
+ }
590
+ let h0 = 1779033703;
591
+ let h1 = 3144134277;
592
+ let h2 = 1013904242;
593
+ let h3 = 2773480762;
594
+ let h4 = 1359893119;
595
+ let h5 = 2600822924;
596
+ let h6 = 528734635;
597
+ let h7 = 1541459225;
598
+ const words = new Array(64);
599
+ for (let offset = 0; offset < bytes.length; offset += 64) {
600
+ for (let index = 0; index < 16; index += 1) {
601
+ const base = offset + index * 4;
602
+ words[index] = (bytes[base] << 24 | bytes[base + 1] << 16 | bytes[base + 2] << 8 | bytes[base + 3]) >>> 0;
603
+ }
604
+ for (let index = 16; index < 64; index += 1) {
605
+ const s0 = rotateRight(words[index - 15], 7) ^ rotateRight(words[index - 15], 18) ^ words[index - 15] >>> 3;
606
+ const s1 = rotateRight(words[index - 2], 17) ^ rotateRight(words[index - 2], 19) ^ words[index - 2] >>> 10;
607
+ words[index] = words[index - 16] + s0 + words[index - 7] + s1 >>> 0;
608
+ }
609
+ let a = h0;
610
+ let b = h1;
611
+ let c = h2;
612
+ let d = h3;
613
+ let e = h4;
614
+ let f = h5;
615
+ let g = h6;
616
+ let h = h7;
617
+ for (let index = 0; index < 64; index += 1) {
618
+ const s1 = rotateRight(e, 6) ^ rotateRight(e, 11) ^ rotateRight(e, 25);
619
+ const ch2 = e & f ^ ~e & g;
620
+ const temp1 = h + s1 + ch2 + SHA256_K[index] + words[index] >>> 0;
621
+ const s0 = rotateRight(a, 2) ^ rotateRight(a, 13) ^ rotateRight(a, 22);
622
+ const maj2 = a & b ^ a & c ^ b & c;
623
+ const temp2 = s0 + maj2 >>> 0;
624
+ h = g;
625
+ g = f;
626
+ f = e;
627
+ e = d + temp1 >>> 0;
628
+ d = c;
629
+ c = b;
630
+ b = a;
631
+ a = temp1 + temp2 >>> 0;
632
+ }
633
+ h0 = h0 + a >>> 0;
634
+ h1 = h1 + b >>> 0;
635
+ h2 = h2 + c >>> 0;
636
+ h3 = h3 + d >>> 0;
637
+ h4 = h4 + e >>> 0;
638
+ h5 = h5 + f >>> 0;
639
+ h6 = h6 + g >>> 0;
640
+ h7 = h7 + h >>> 0;
641
+ }
642
+ return [h0, h1, h2, h3, h4, h5, h6, h7].map((value) => value.toString(16).padStart(8, "0")).join("");
643
+ }
644
+ function rotateRight(value, bits) {
645
+ return value >>> bits | value << 32 - bits;
646
+ }
647
+ function utf8Bytes(input) {
648
+ return Array.from(new TextEncoder().encode(input));
649
+ }
650
+
651
+ // src/runtime/context/PluginStateContext.tsx
297
652
  import { Fragment as Fragment2, jsx as jsx4, jsxs } from "react/jsx-runtime";
298
653
  var PluginStateContext = createContext4(null);
654
+ var GAMEPLAY_BROWSER_SCOPE_ID = "runtime";
655
+ var BROWSER_PROJECTION_DIGEST_ATTRIBUTE = "data-dreamboard-projection-digest";
656
+ function RuntimeSemanticProjectionMarker() {
657
+ const state = usePluginState((snapshot) => snapshot);
658
+ return /* @__PURE__ */ jsx4(SemanticProjectionMarker, { state });
659
+ }
660
+ function SemanticProjectionMarker({
661
+ state
662
+ }) {
663
+ const digest = semanticProjectionDigestForState(state);
664
+ if (!digest) {
665
+ return null;
666
+ }
667
+ return /* @__PURE__ */ jsx4(
668
+ "span",
669
+ {
670
+ "aria-hidden": "true",
671
+ style: { display: "none" },
672
+ ...{
673
+ [BROWSER_INTERACTION_ATTRIBUTES.protocol]: DREAMBOARD_BROWSER_INTERACTION_PROTOCOL_VERSION,
674
+ [BROWSER_INTERACTION_ATTRIBUTES.surface]: GAMEPLAY_BROWSER_INTERACTION_SURFACE,
675
+ [BROWSER_INTERACTION_ATTRIBUTES.scope]: GAMEPLAY_BROWSER_SCOPE_ID,
676
+ [BROWSER_INTERACTION_ATTRIBUTES.role]: "projection",
677
+ [BROWSER_PROJECTION_DIGEST_ATTRIBUTE]: digest
678
+ }
679
+ }
680
+ );
681
+ }
299
682
  function usePluginState(selector) {
300
683
  const runtime = useRuntimeContext();
301
684
  const subscribe = (onStoreChange) => {
@@ -345,7 +728,7 @@ function usePluginActions() {
345
728
  };
346
729
  }
347
730
 
348
- // src/runtime-internal/utils/interaction-inputs.ts
731
+ // src/runtime/utils/interaction-inputs.ts
349
732
  function interactionInputKeys(descriptor) {
350
733
  return descriptor.inputs.map((input) => input.key);
351
734
  }
@@ -650,7 +1033,7 @@ function pluralize(word, count) {
650
1033
  return count === 1 ? word : `${word}s`;
651
1034
  }
652
1035
 
653
- // src/runtime-internal/utils/interaction-router.ts
1036
+ // src/runtime/utils/interaction-router.ts
654
1037
  function applyInteractionDraftMutation(store, descriptor, mutations) {
655
1038
  const originalDraft = {
656
1039
  ...store.getDraft(descriptor.interactionKey)
@@ -797,7 +1180,7 @@ function claimInteractionSubmit(store, descriptor) {
797
1180
  return store.claimSubmitting(descriptor.interactionKey);
798
1181
  }
799
1182
 
800
- // src/runtime-internal/utils/interaction-status.ts
1183
+ // src/runtime/utils/interaction-status.ts
801
1184
  function isInteractionAvailable(descriptor) {
802
1185
  return descriptor?.availability.status === "available";
803
1186
  }
@@ -806,7 +1189,7 @@ function interactionUnavailableReason(descriptor) {
806
1189
  return availability && availability.status !== "available" ? availability.reason : void 0;
807
1190
  }
808
1191
 
809
- // src/runtime-internal/utils/card-intent-adapter.ts
1192
+ // src/runtime/utils/card-intent-adapter.ts
810
1193
  var DROP_TARGET_PREFIX = "dreamboard:drop";
811
1194
  function encodeRuntimeDropTargetKind(kind, value) {
812
1195
  return `${DROP_TARGET_PREFIX}:kind:${kind}:${value}`;
@@ -1061,7 +1444,7 @@ function selectedCardIdsForZone(store, zone, state) {
1061
1444
  return [...result];
1062
1445
  }
1063
1446
 
1064
- // src/runtime-internal/primitives/hand-intent-adapter.ts
1447
+ // src/runtime/primitives/hand-intent-adapter.ts
1065
1448
  function decodeAuthoredCardIntent(intent) {
1066
1449
  if (intent.type !== "drop") {
1067
1450
  return intent;
@@ -1139,11 +1522,11 @@ function useCardIntentAdapter({
1139
1522
  );
1140
1523
  }
1141
1524
 
1142
- // src/runtime-internal/primitives/game.tsx
1525
+ // src/runtime/primitives/game.tsx
1143
1526
  import { createContext as createContext5, useContext as useContext5, useMemo as useMemo5 } from "react";
1144
1527
  import { useStore as useStore2 } from "zustand";
1145
1528
 
1146
- // src/runtime-internal/hooks/useActivePlayers.ts
1529
+ // src/runtime/hooks/useActivePlayers.ts
1147
1530
  function useActivePlayers() {
1148
1531
  return usePluginState((state) => {
1149
1532
  const simultaneous = state.gameplay.simultaneousPhase;
@@ -1154,7 +1537,7 @@ function useActivePlayers() {
1154
1537
  });
1155
1538
  }
1156
1539
 
1157
- // src/runtime-internal/hooks/useGameSelector.ts
1540
+ // src/runtime/hooks/useGameSelector.ts
1158
1541
  import { useRef, useSyncExternalStore as useSyncExternalStore2 } from "react";
1159
1542
  function defaultEquality(left, right) {
1160
1543
  return Object.is(left, right);
@@ -1218,15 +1601,15 @@ function useGameSelector(selector, equalityFn = defaultEquality) {
1218
1601
  return useSyncExternalStore2(subscribe, getSnapshot, getSnapshot);
1219
1602
  }
1220
1603
 
1221
- // src/runtime-internal/hooks/useGameView.ts
1604
+ // src/runtime/hooks/useGameView.ts
1222
1605
  function useGameView() {
1223
1606
  return useGameSelector((view) => view);
1224
1607
  }
1225
1608
 
1226
- // src/runtime-internal/hooks/usePlayerInfo.ts
1609
+ // src/runtime/hooks/usePlayerInfo.ts
1227
1610
  import { useMemo as useMemo3 } from "react";
1228
1611
 
1229
- // src/runtime-internal/hooks/useLobby.ts
1612
+ // src/runtime/hooks/useLobby.ts
1230
1613
  import { useState as useState3, useEffect as useEffect3 } from "react";
1231
1614
  function useLobbyState() {
1232
1615
  const runtime = useRuntimeContext();
@@ -1265,7 +1648,7 @@ function useLobby() {
1265
1648
  return lobbyState;
1266
1649
  }
1267
1650
 
1268
- // src/runtime-internal/hooks/usePlayerInfo.ts
1651
+ // src/runtime/hooks/usePlayerInfo.ts
1269
1652
  function usePlayerInfo() {
1270
1653
  const lobby = useLobbyState();
1271
1654
  return useMemo3(() => {
@@ -1286,7 +1669,7 @@ function usePlayerInfo() {
1286
1669
  }, [lobby]);
1287
1670
  }
1288
1671
 
1289
- // src/runtime-internal/hooks/usePlayerTurnOrder.ts
1672
+ // src/runtime/hooks/usePlayerTurnOrder.ts
1290
1673
  import { useMemo as useMemo4 } from "react";
1291
1674
  function usePlayerTurnOrder() {
1292
1675
  const lobby = useLobby();
@@ -1296,7 +1679,7 @@ function usePlayerTurnOrder() {
1296
1679
  }, [lobby]);
1297
1680
  }
1298
1681
 
1299
- // src/runtime-internal/utils/interaction-labels.ts
1682
+ // src/runtime/utils/interaction-labels.ts
1300
1683
  function humanizeInteractionId(id) {
1301
1684
  if (!id) return id;
1302
1685
  const withSpaces = id.replace(/[-_]+/g, " ").replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2").trim();
@@ -1309,7 +1692,7 @@ function interactionLabel(descriptor) {
1309
1692
  );
1310
1693
  }
1311
1694
 
1312
- // src/runtime-internal/primitives/game.tsx
1695
+ // src/runtime/primitives/game.tsx
1313
1696
  import { Fragment as Fragment3, jsx as jsx5 } from "react/jsx-runtime";
1314
1697
  var GameActionErrorContext = createContext5(
1315
1698
  null
@@ -1487,78 +1870,14 @@ var Game = {
1487
1870
  Chrome: GameChrome
1488
1871
  };
1489
1872
 
1490
- // src/runtime-internal/primitives/primitive-props.tsx
1491
- import {
1492
- cloneElement,
1493
- isValidElement
1494
- } from "react";
1495
- import { jsx as jsx6 } from "react/jsx-runtime";
1496
- function composeEventHandlers(authorHandler, primitiveHandler) {
1497
- if (!authorHandler) return primitiveHandler;
1498
- if (!primitiveHandler) return authorHandler;
1499
- return (event) => {
1500
- authorHandler(event);
1501
- if (!event.defaultPrevented) {
1502
- primitiveHandler(event);
1503
- }
1504
- };
1505
- }
1506
- function renderPrimitive(tagName, props) {
1507
- const { asChild, children, ...primitiveProps } = props;
1508
- if (asChild) {
1509
- if (!isValidElement(children)) {
1510
- throw new Error(
1511
- "asChild requires exactly one valid React element child."
1512
- );
1513
- }
1514
- const element = children;
1515
- const childProps = element.props;
1516
- return cloneElement(element, {
1517
- ...primitiveProps,
1518
- ...childProps,
1519
- className: [primitiveProps.className, childProps.className].filter(Boolean).join(" "),
1520
- style: {
1521
- ...primitiveProps.style ?? {},
1522
- ...childProps.style ?? {}
1523
- },
1524
- onClick: composeEventHandlers(
1525
- childProps.onClick,
1526
- primitiveProps.onClick
1527
- ),
1528
- onPointerDown: composeEventHandlers(
1529
- childProps.onPointerDown,
1530
- primitiveProps.onPointerDown
1531
- ),
1532
- onPointerMove: composeEventHandlers(
1533
- childProps.onPointerMove,
1534
- primitiveProps.onPointerMove
1535
- ),
1536
- onPointerUp: composeEventHandlers(
1537
- childProps.onPointerUp,
1538
- primitiveProps.onPointerUp
1539
- ),
1540
- onPointerCancel: composeEventHandlers(
1541
- childProps.onPointerCancel,
1542
- primitiveProps.onPointerCancel
1543
- ),
1544
- onChange: composeEventHandlers(
1545
- childProps.onChange,
1546
- primitiveProps.onChange
1547
- )
1548
- });
1549
- }
1550
- const Tag = tagName;
1551
- return /* @__PURE__ */ jsx6(Tag, { ...primitiveProps, children });
1552
- }
1553
-
1554
- // src/runtime-internal/primitives/zone.tsx
1873
+ // src/runtime/primitives/zone.tsx
1555
1874
  import {
1556
1875
  createContext as createContext6,
1557
1876
  useContext as useContext6,
1558
1877
  useMemo as useMemo6
1559
1878
  } from "react";
1560
1879
 
1561
- // src/runtime-internal/primitives/interaction-submit.ts
1880
+ // src/runtime/primitives/interaction-submit.ts
1562
1881
  async function runInteractionAction(action, {
1563
1882
  onSuccess,
1564
1883
  onError,
@@ -1597,8 +1916,8 @@ function submitInteractionParams(handle, params, callbacks = {}, options = {}) {
1597
1916
  });
1598
1917
  }
1599
1918
 
1600
- // src/runtime-internal/primitives/zone.tsx
1601
- import { Fragment as Fragment4, jsx as jsx7 } from "react/jsx-runtime";
1919
+ // src/runtime/primitives/zone.tsx
1920
+ import { Fragment as Fragment4, jsx as jsx6 } from "react/jsx-runtime";
1602
1921
  var ZoneContext = createContext6(null);
1603
1922
  var ZoneCardContext = createContext6(null);
1604
1923
  var ZonePileContext = createContext6(null);
@@ -1634,7 +1953,7 @@ function ZoneRoot({
1634
1953
  () => ({ zone, snapshot }),
1635
1954
  [snapshot, zone]
1636
1955
  );
1637
- return /* @__PURE__ */ jsx7(ZoneContext.Provider, { value, children: renderPrimitive("div", {
1956
+ return /* @__PURE__ */ jsx6(ZoneContext.Provider, { value, children: renderPrimitive("div", {
1638
1957
  ...props,
1639
1958
  "data-dreamboard-zone-root": "",
1640
1959
  "data-zone": zone,
@@ -1644,7 +1963,7 @@ function ZoneRoot({
1644
1963
  }
1645
1964
  function ZoneList({ children, empty, sort, ...props }) {
1646
1965
  const { zone, items, isEmpty } = useZoneCards({ sort });
1647
- const renderedChildren = typeof children === "function" ? isEmpty ? empty : items.map((item) => /* @__PURE__ */ jsx7(ZoneItem, { card: item, children: children(item) }, item.id)) : isEmpty && empty !== void 0 ? empty : children;
1966
+ const renderedChildren = typeof children === "function" ? isEmpty ? empty : items.map((item) => /* @__PURE__ */ jsx6(ZoneItem, { card: item, children: children(item) }, item.id)) : isEmpty && empty !== void 0 ? empty : children;
1648
1967
  return renderPrimitive("div", {
1649
1968
  ...props,
1650
1969
  role: props.role ?? "list",
@@ -1684,7 +2003,7 @@ function ZoneItem({ card, children, ...props }) {
1684
2003
  () => ({ zone, cardId: item.id }),
1685
2004
  [item.id, zone]
1686
2005
  );
1687
- return /* @__PURE__ */ jsx7(ZoneCardContext.Provider, { value: cardContext, children: renderPrimitive("div", {
2006
+ return /* @__PURE__ */ jsx6(ZoneCardContext.Provider, { value: cardContext, children: renderPrimitive("div", {
1688
2007
  ...props,
1689
2008
  role: props.role ?? "listitem",
1690
2009
  "data-dreamboard-zone-item": "",
@@ -1705,23 +2024,23 @@ function ZoneCardAtContent({
1705
2024
  }) {
1706
2025
  const { zone, snapshot } = useZonePrimitiveContext();
1707
2026
  const cardIndex = resolveZoneCardIndex(snapshot, index);
1708
- if (cardIndex === null) return /* @__PURE__ */ jsx7(Fragment4, { children: empty });
2027
+ if (cardIndex === null) return /* @__PURE__ */ jsx6(Fragment4, { children: empty });
1709
2028
  const cardId = snapshot?.cardIds[cardIndex];
1710
- if (!cardId) return /* @__PURE__ */ jsx7(Fragment4, { children: empty });
2029
+ if (!cardId) return /* @__PURE__ */ jsx6(Fragment4, { children: empty });
1711
2030
  const card = createZoneCardRenderItem(zone, snapshot, cardId, cardIndex);
1712
- return /* @__PURE__ */ jsx7(ZoneItem, { card, ...props, children: typeof children === "function" ? children(card) : children });
2031
+ return /* @__PURE__ */ jsx6(ZoneItem, { card, ...props, children: typeof children === "function" ? children(card) : children });
1713
2032
  }
1714
2033
  function ZoneCardAt({
1715
2034
  zone,
1716
2035
  ...props
1717
2036
  }) {
1718
2037
  if (zone) {
1719
- return /* @__PURE__ */ jsx7(ZoneRoot, { zone, children: /* @__PURE__ */ jsx7(ZoneCardAtContent, { ...props }) });
2038
+ return /* @__PURE__ */ jsx6(ZoneRoot, { zone, children: /* @__PURE__ */ jsx6(ZoneCardAtContent, { ...props }) });
1720
2039
  }
1721
- return /* @__PURE__ */ jsx7(ZoneCardAtContent, { ...props });
2040
+ return /* @__PURE__ */ jsx6(ZoneCardAtContent, { ...props });
1722
2041
  }
1723
2042
  function ZoneTopCard(props) {
1724
- return /* @__PURE__ */ jsx7(ZoneCardAt, { ...props, index: 0 });
2043
+ return /* @__PURE__ */ jsx6(ZoneCardAt, { ...props, index: 0 });
1725
2044
  }
1726
2045
  function ZoneCardAction({
1727
2046
  card,
@@ -1824,7 +2143,7 @@ function ZonePileRoot({
1824
2143
  children,
1825
2144
  ...props
1826
2145
  }) {
1827
- return /* @__PURE__ */ jsx7(ZoneRoot, { zone, ...props, children: /* @__PURE__ */ jsx7(
2146
+ return /* @__PURE__ */ jsx6(ZoneRoot, { zone, ...props, children: /* @__PURE__ */ jsx6(
1828
2147
  ZonePileProvider,
1829
2148
  {
1830
2149
  emptyDescription,
@@ -1864,7 +2183,7 @@ function ZonePileProvider({
1864
2183
  }),
1865
2184
  [cards, count, description, hasVisibleCards, isHidden, items, label, zone]
1866
2185
  );
1867
- return /* @__PURE__ */ jsx7(ZonePileContext.Provider, { value, children });
2186
+ return /* @__PURE__ */ jsx6(ZonePileContext.Provider, { value, children });
1868
2187
  }
1869
2188
  function ZonePileTrigger({ children, ...props }) {
1870
2189
  const pile = useZonePileContext();
@@ -1915,7 +2234,7 @@ function ZonePileDescription({
1915
2234
  function ZonePileCards({ renderCard, ...props }) {
1916
2235
  const pile = useZonePileContext();
1917
2236
  if (!pile.hasVisibleCards) return null;
1918
- return /* @__PURE__ */ jsx7(ZoneList, { ...props, children: pile.items.map((card) => /* @__PURE__ */ jsx7(ZoneItem, { card, children: renderCard(card) }, card.id)) });
2237
+ return /* @__PURE__ */ jsx6(ZoneList, { ...props, children: pile.items.map((card) => /* @__PURE__ */ jsx6(ZoneItem, { card, children: renderCard(card) }, card.id)) });
1919
2238
  }
1920
2239
  function indexOfCard(snapshot, cardId) {
1921
2240
  return snapshot?.cardIds.indexOf(cardId) ?? -1;
@@ -2030,7 +2349,7 @@ var Zone = {
2030
2349
  useZoneCards
2031
2350
  };
2032
2351
 
2033
- // src/runtime-internal/primitives/hand-surface.tsx
2352
+ // src/runtime/primitives/hand-surface.tsx
2034
2353
  import {
2035
2354
  Fragment as Fragment5,
2036
2355
  useCallback as useCallback2,
@@ -2040,7 +2359,7 @@ import {
2040
2359
  } from "react";
2041
2360
  import { useStore as useStore3 } from "zustand";
2042
2361
  import { useShallow as useShallow2 } from "zustand/shallow";
2043
- import { jsx as jsx8, jsxs as jsxs2 } from "react/jsx-runtime";
2362
+ import { jsx as jsx7, jsxs as jsxs2 } from "react/jsx-runtime";
2044
2363
  function HandSurfaceView({
2045
2364
  zone,
2046
2365
  cards,
@@ -2167,7 +2486,7 @@ function HandSurfaceView({
2167
2486
  }, [selectionSummary]);
2168
2487
  const summaryContent = renderSummary ? renderSummary(selectionSummary) : null;
2169
2488
  const actionsNode = renderActions ? renderActions(selectionSummary) : null;
2170
- const actionsContent = actionsNode !== null && actionsNode !== void 0 ? /* @__PURE__ */ jsx8(
2489
+ const actionsContent = actionsNode !== null && actionsNode !== void 0 ? /* @__PURE__ */ jsx7(
2171
2490
  "div",
2172
2491
  {
2173
2492
  "data-dreamboard-hand-actions": "",
@@ -2186,7 +2505,7 @@ function HandSurfaceView({
2186
2505
  },
2187
2506
  [route]
2188
2507
  );
2189
- const handView = /* @__PURE__ */ jsx8(
2508
+ const handView = /* @__PURE__ */ jsx7(
2190
2509
  HandView,
2191
2510
  {
2192
2511
  cards: viewCards,
@@ -2210,7 +2529,7 @@ function HandSurfaceView({
2210
2529
  return handView;
2211
2530
  }
2212
2531
  return /* @__PURE__ */ jsxs2(Fragment5, { children: [
2213
- summaryContent !== null ? /* @__PURE__ */ jsx8(
2532
+ summaryContent !== null ? /* @__PURE__ */ jsx7(
2214
2533
  "div",
2215
2534
  {
2216
2535
  "data-dreamboard-runtime-hand-summary": "",
@@ -2224,7 +2543,7 @@ function HandSurfaceView({
2224
2543
  actionsContent
2225
2544
  ] });
2226
2545
  }
2227
- const targets = dropTargets.map((target) => /* @__PURE__ */ jsx8(
2546
+ const targets = dropTargets.map((target) => /* @__PURE__ */ jsx7(
2228
2547
  CardDropTargetView,
2229
2548
  {
2230
2549
  targetId: target.targetId,
@@ -2238,7 +2557,7 @@ function HandSurfaceView({
2238
2557
  target.targetId
2239
2558
  ));
2240
2559
  return /* @__PURE__ */ jsxs2(CardDragSurface, { onCardIntent: handleIntent, children: [
2241
- summaryContent !== null ? /* @__PURE__ */ jsx8(
2560
+ summaryContent !== null ? /* @__PURE__ */ jsx7(
2242
2561
  "div",
2243
2562
  {
2244
2563
  "data-dreamboard-runtime-hand-summary": "",
@@ -2248,7 +2567,7 @@ function HandSurfaceView({
2248
2567
  children: summaryContent
2249
2568
  }
2250
2569
  ) : null,
2251
- renderDropTargets ? renderDropTargets(/* @__PURE__ */ jsx8(Fragment5, { children: targets })) : /* @__PURE__ */ jsx8("div", { "data-dreamboard-runtime-drop-row": "", className: "flex gap-2 mb-2", children: targets }),
2570
+ renderDropTargets ? renderDropTargets(/* @__PURE__ */ jsx7(Fragment5, { children: targets })) : /* @__PURE__ */ jsx7("div", { "data-dreamboard-runtime-drop-row": "", className: "flex gap-2 mb-2", children: targets }),
2252
2571
  handView,
2253
2572
  actionsContent
2254
2573
  ] });
@@ -2314,7 +2633,7 @@ function HandStagingView({
2314
2633
  [route]
2315
2634
  );
2316
2635
  if (slotCount <= 0 && cards.length === 0) return null;
2317
- return /* @__PURE__ */ jsx8(
2636
+ return /* @__PURE__ */ jsx7(
2318
2637
  StagingZone,
2319
2638
  {
2320
2639
  cards,
@@ -2345,7 +2664,7 @@ function descriptorsHaveDestinationInput(state) {
2345
2664
  return false;
2346
2665
  }
2347
2666
 
2348
- // src/runtime-internal/primitives/board.tsx
2667
+ // src/runtime/primitives/board.tsx
2349
2668
  import {
2350
2669
  createContext as createContext7,
2351
2670
  useContext as useContext7,
@@ -2353,11 +2672,11 @@ import {
2353
2672
  } from "react";
2354
2673
  import { useStore as useStore5 } from "zustand";
2355
2674
 
2356
- // src/runtime-internal/hooks/useBoardInteractions.ts
2675
+ // src/runtime/hooks/useBoardInteractions.ts
2357
2676
  import { useCallback as useCallback3, useMemo as useMemo8 } from "react";
2358
2677
  import { useStore as useStore4 } from "zustand";
2359
2678
 
2360
- // src/runtime-internal/errors/ValidationError.ts
2679
+ // src/ui/errors/ValidationError.ts
2361
2680
  var ValidationError = class extends Error {
2362
2681
  constructor(errorCode, message) {
2363
2682
  super(message || errorCode || "Validation failed");
@@ -2373,7 +2692,374 @@ function validationErrorFromUnknown(error, fallbackMessage = "Interaction submis
2373
2692
  return new ValidationError(errorCode, message);
2374
2693
  }
2375
2694
 
2376
- // src/runtime-internal/hooks/useBoardInteractions.ts
2695
+ // src/runtime/utils/interaction-draft-digest.ts
2696
+ function interactionDraftDigestForValues(descriptor, values) {
2697
+ if (descriptor.descriptorDigest === void 0 || descriptor.actorSeat === void 0 || descriptor.draftDigest === void 0) {
2698
+ return void 0;
2699
+ }
2700
+ const defaults = defaultsForDescriptor(descriptor);
2701
+ return draftDigest({
2702
+ actorSeat: descriptor.actorSeat,
2703
+ descriptorDigest: descriptor.descriptorDigest,
2704
+ interactionId: descriptor.interactionId,
2705
+ interactionKey: descriptor.interactionKey,
2706
+ values: {
2707
+ ...defaults,
2708
+ ...toCanonicalJson2(values)
2709
+ }
2710
+ });
2711
+ }
2712
+ function draftDigest({
2713
+ actorSeat,
2714
+ descriptorDigest,
2715
+ interactionId,
2716
+ interactionKey,
2717
+ values
2718
+ }) {
2719
+ return hashJson2({
2720
+ digestVersion: "interaction-draft@2",
2721
+ actorSeat,
2722
+ descriptorDigest,
2723
+ emitted: false,
2724
+ interactionId,
2725
+ interactionKey,
2726
+ values
2727
+ });
2728
+ }
2729
+ function defaultsForDescriptor(descriptor) {
2730
+ return Object.fromEntries(
2731
+ descriptor.inputs.flatMap(
2732
+ (input) => input.defaultValue === void 0 ? [] : [[input.key, toCanonicalJson2(input.defaultValue)]]
2733
+ )
2734
+ );
2735
+ }
2736
+ function toCanonicalJson2(value) {
2737
+ if (value === null || typeof value === "boolean" || typeof value === "string") {
2738
+ return value;
2739
+ }
2740
+ if (typeof value === "number") {
2741
+ return value;
2742
+ }
2743
+ if (Array.isArray(value)) {
2744
+ return value.map((item) => toCanonicalJson2(item));
2745
+ }
2746
+ if (typeof value === "object") {
2747
+ return Object.fromEntries(
2748
+ Object.entries(value).filter(([, item]) => item !== void 0).map(([key, item]) => [key, toCanonicalJson2(item)])
2749
+ );
2750
+ }
2751
+ return null;
2752
+ }
2753
+ function hashJson2(value) {
2754
+ return `sha256:${sha256Hex2(canonicalJson2(value))}`;
2755
+ }
2756
+ function canonicalJson2(value) {
2757
+ return JSON.stringify(canonicalizeJson2(value));
2758
+ }
2759
+ function canonicalizeJson2(value) {
2760
+ if (value === null || typeof value === "boolean" || typeof value === "string") {
2761
+ return value;
2762
+ }
2763
+ if (typeof value === "number") {
2764
+ if (!Number.isFinite(value)) {
2765
+ throw new Error("canonical JSON contains a non-finite number");
2766
+ }
2767
+ return value;
2768
+ }
2769
+ if (Array.isArray(value)) {
2770
+ return value.map((item) => canonicalizeJson2(item));
2771
+ }
2772
+ return Object.fromEntries(
2773
+ Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, item]) => [key, canonicalizeJson2(item)])
2774
+ );
2775
+ }
2776
+ function sha256Hex2(input) {
2777
+ const bytes = utf8Bytes2(input);
2778
+ const bitLength = bytes.length * 8;
2779
+ bytes.push(128);
2780
+ while (bytes.length % 64 !== 56) {
2781
+ bytes.push(0);
2782
+ }
2783
+ for (let shift = 56; shift >= 0; shift -= 8) {
2784
+ bytes.push(Math.floor(bitLength / 2 ** shift) & 255);
2785
+ }
2786
+ let h0 = 1779033703;
2787
+ let h1 = 3144134277;
2788
+ let h2 = 1013904242;
2789
+ let h3 = 2773480762;
2790
+ let h4 = 1359893119;
2791
+ let h5 = 2600822924;
2792
+ let h6 = 528734635;
2793
+ let h7 = 1541459225;
2794
+ const words = new Array(64);
2795
+ for (let offset = 0; offset < bytes.length; offset += 64) {
2796
+ for (let i = 0; i < 16; i += 1) {
2797
+ words[i] = (bytes[offset + i * 4] ?? 0) << 24 | (bytes[offset + i * 4 + 1] ?? 0) << 16 | (bytes[offset + i * 4 + 2] ?? 0) << 8 | (bytes[offset + i * 4 + 3] ?? 0);
2798
+ }
2799
+ for (let i = 16; i < 64; i += 1) {
2800
+ words[i] = smallSigma1(words[i - 2] ?? 0) + (words[i - 7] ?? 0) + smallSigma0(words[i - 15] ?? 0) + (words[i - 16] ?? 0) >>> 0;
2801
+ }
2802
+ let a = h0;
2803
+ let b = h1;
2804
+ let c = h2;
2805
+ let d = h3;
2806
+ let e = h4;
2807
+ let f = h5;
2808
+ let g = h6;
2809
+ let h = h7;
2810
+ for (let i = 0; i < 64; i += 1) {
2811
+ const t1 = h + bigSigma1(e) + ch(e, f, g) + K[i] + (words[i] ?? 0) >>> 0;
2812
+ const t2 = bigSigma0(a) + maj(a, b, c) >>> 0;
2813
+ h = g;
2814
+ g = f;
2815
+ f = e;
2816
+ e = d + t1 >>> 0;
2817
+ d = c;
2818
+ c = b;
2819
+ b = a;
2820
+ a = t1 + t2 >>> 0;
2821
+ }
2822
+ h0 = h0 + a >>> 0;
2823
+ h1 = h1 + b >>> 0;
2824
+ h2 = h2 + c >>> 0;
2825
+ h3 = h3 + d >>> 0;
2826
+ h4 = h4 + e >>> 0;
2827
+ h5 = h5 + f >>> 0;
2828
+ h6 = h6 + g >>> 0;
2829
+ h7 = h7 + h >>> 0;
2830
+ }
2831
+ return [h0, h1, h2, h3, h4, h5, h6, h7].map((word) => word.toString(16).padStart(8, "0")).join("");
2832
+ }
2833
+ function utf8Bytes2(input) {
2834
+ return Array.from(new TextEncoder().encode(input));
2835
+ }
2836
+ function rightRotate(value, bits) {
2837
+ return value >>> bits | value << 32 - bits;
2838
+ }
2839
+ function ch(x, y, z) {
2840
+ return x & y ^ ~x & z;
2841
+ }
2842
+ function maj(x, y, z) {
2843
+ return x & y ^ x & z ^ y & z;
2844
+ }
2845
+ function bigSigma0(x) {
2846
+ return rightRotate(x, 2) ^ rightRotate(x, 13) ^ rightRotate(x, 22);
2847
+ }
2848
+ function bigSigma1(x) {
2849
+ return rightRotate(x, 6) ^ rightRotate(x, 11) ^ rightRotate(x, 25);
2850
+ }
2851
+ function smallSigma0(x) {
2852
+ return rightRotate(x, 7) ^ rightRotate(x, 18) ^ x >>> 3;
2853
+ }
2854
+ function smallSigma1(x) {
2855
+ return rightRotate(x, 17) ^ rightRotate(x, 19) ^ x >>> 10;
2856
+ }
2857
+ var K = [
2858
+ 1116352408,
2859
+ 1899447441,
2860
+ 3049323471,
2861
+ 3921009573,
2862
+ 961987163,
2863
+ 1508970993,
2864
+ 2453635748,
2865
+ 2870763221,
2866
+ 3624381080,
2867
+ 310598401,
2868
+ 607225278,
2869
+ 1426881987,
2870
+ 1925078388,
2871
+ 2162078206,
2872
+ 2614888103,
2873
+ 3248222580,
2874
+ 3835390401,
2875
+ 4022224774,
2876
+ 264347078,
2877
+ 604807628,
2878
+ 770255983,
2879
+ 1249150122,
2880
+ 1555081692,
2881
+ 1996064986,
2882
+ 2554220882,
2883
+ 2821834349,
2884
+ 2952996808,
2885
+ 3210313671,
2886
+ 3336571891,
2887
+ 3584528711,
2888
+ 113926993,
2889
+ 338241895,
2890
+ 666307205,
2891
+ 773529912,
2892
+ 1294757372,
2893
+ 1396182291,
2894
+ 1695183700,
2895
+ 1986661051,
2896
+ 2177026350,
2897
+ 2456956037,
2898
+ 2730485921,
2899
+ 2820302411,
2900
+ 3259730800,
2901
+ 3345764771,
2902
+ 3516065817,
2903
+ 3600352804,
2904
+ 4094571909,
2905
+ 275423344,
2906
+ 430227734,
2907
+ 506948616,
2908
+ 659060556,
2909
+ 883997877,
2910
+ 958139571,
2911
+ 1322822218,
2912
+ 1537002063,
2913
+ 1747873779,
2914
+ 1955562222,
2915
+ 2024104815,
2916
+ 2227730452,
2917
+ 2361852424,
2918
+ 2428436474,
2919
+ 2756734187,
2920
+ 3204031479,
2921
+ 3329325298
2922
+ ];
2923
+
2924
+ // src/runtime/utils/browser-interaction-effects.ts
2925
+ function gameplayCandidateMetadata(input) {
2926
+ const inputDescriptor = resolvedInputByKey(
2927
+ input.descriptor,
2928
+ input.inputKey,
2929
+ input.draftValues
2930
+ );
2931
+ if (!inputDescriptor) return { semanticEffects: [] };
2932
+ const currentValue = input.draftValues[input.inputKey];
2933
+ const beforeSelected = isCandidateSelected(
2934
+ currentValue,
2935
+ input.candidateValue,
2936
+ inputDescriptor
2937
+ );
2938
+ const afterSelected = input.intent === "toggle" && isManySelection(inputDescriptor) ? !beforeSelected : true;
2939
+ return {
2940
+ semanticEffects: [
2941
+ gameplaySetCandidateEffect({
2942
+ inputKey: input.inputKey,
2943
+ candidateValue: input.candidateValue,
2944
+ beforeSelected,
2945
+ afterSelected
2946
+ })
2947
+ ]
2948
+ };
2949
+ }
2950
+ function gameplayResourceMetadata(input) {
2951
+ return {
2952
+ semanticEffects: [
2953
+ gameplayAdjustResourceEffect({
2954
+ inputKey: input.inputKey,
2955
+ resourceKey: input.resourceKey,
2956
+ delta: input.delta
2957
+ })
2958
+ ]
2959
+ };
2960
+ }
2961
+ function gameplayScalarStepMetadata(input) {
2962
+ return {
2963
+ semanticEffects: [
2964
+ gameplaySetScalarEffect({
2965
+ inputKey: input.inputKey,
2966
+ value: input.value
2967
+ })
2968
+ ]
2969
+ };
2970
+ }
2971
+ function gameplayScalarFillMetadata(input) {
2972
+ return {
2973
+ acceptedEffectPatterns: [
2974
+ boundedScalarPattern(input.inputKey, input.domain)
2975
+ ]
2976
+ };
2977
+ }
2978
+ function gameplaySubmitMetadata(input) {
2979
+ const invoke = input.explicitParams === true || input.descriptor.commit.mode !== "manual";
2980
+ return invoke ? { intent: "invoke", semanticEffects: [gameplayInvokeEffect()] } : { intent: "submit", semanticEffects: [gameplayCommitEffect()] };
2981
+ }
2982
+ function gameplayPreparationPatternsForDescriptor(descriptor, draftValues) {
2983
+ const patterns = [];
2984
+ for (const rawInput of descriptor.inputs) {
2985
+ const input = resolveInputDomain(rawInput, draftValues);
2986
+ switch (input.domain.type) {
2987
+ case "choice":
2988
+ case "choiceList":
2989
+ case "cardTarget":
2990
+ case "boardTarget":
2991
+ patterns.push({
2992
+ kind: "match",
2993
+ effectKind: "setCandidate",
2994
+ fields: { inputKey: input.key }
2995
+ });
2996
+ break;
2997
+ case "resourceMap":
2998
+ patterns.push({
2999
+ kind: "match",
3000
+ effectKind: "adjustResource",
3001
+ fields: { inputKey: input.key }
3002
+ });
3003
+ break;
3004
+ case "boundedNumber":
3005
+ patterns.push(boundedScalarPattern(input.key, input.domain));
3006
+ break;
3007
+ }
3008
+ }
3009
+ return dedupePatterns(patterns);
3010
+ }
3011
+ function boundedScalarPattern(inputKey, domain) {
3012
+ const min = domain.min ?? 0;
3013
+ const max = domain.max;
3014
+ return {
3015
+ kind: "match",
3016
+ effectKind: "setScalar",
3017
+ fields: { inputKey },
3018
+ scalar: {
3019
+ field: "value",
3020
+ min,
3021
+ ...max !== void 0 && Number.isFinite(max) ? { max } : {},
3022
+ ...scalarIsInteger(domain) ? { integer: true } : {}
3023
+ }
3024
+ };
3025
+ }
3026
+ function resolvedInputByKey(descriptor, inputKey, draftValues) {
3027
+ const input = inputByKey(descriptor, inputKey);
3028
+ return input ? resolveInputDomain(input, draftValues) : void 0;
3029
+ }
3030
+ function isCandidateSelected(currentValue, candidateValue, input) {
3031
+ if (isTargetDomain(input.domain) && input.domain.selection?.mode === "many") {
3032
+ return valueArrayIncludes(currentValue, candidateValue);
3033
+ }
3034
+ if (input.domain.type === "choiceList") {
3035
+ return valueArrayIncludes(currentValue, candidateValue);
3036
+ }
3037
+ return String(currentValue) === String(candidateValue);
3038
+ }
3039
+ function isManySelection(input) {
3040
+ if (input.domain.type === "choiceList") return true;
3041
+ return isTargetDomain(input.domain) && input.domain.selection?.mode === "many";
3042
+ }
3043
+ function valueArrayIncludes(currentValue, candidateValue) {
3044
+ return Array.isArray(currentValue) && currentValue.some((item) => String(item) === String(candidateValue));
3045
+ }
3046
+ function scalarIsInteger(domain) {
3047
+ const step = domain.step ?? 1;
3048
+ return Number.isInteger(step) && Number.isInteger(domain.min ?? 0) && (domain.max === void 0 || Number.isInteger(domain.max));
3049
+ }
3050
+ function dedupePatterns(patterns) {
3051
+ const seen = /* @__PURE__ */ new Set();
3052
+ const result = [];
3053
+ for (const pattern of patterns) {
3054
+ const key = JSON.stringify(pattern);
3055
+ if (seen.has(key)) continue;
3056
+ seen.add(key);
3057
+ result.push(pattern);
3058
+ }
3059
+ return result;
3060
+ }
3061
+
3062
+ // src/runtime/hooks/useBoardInteractions.ts
2377
3063
  var BoardInteractionConflictError = class extends Error {
2378
3064
  name = "BoardInteractionConflictError";
2379
3065
  targetKind;
@@ -2527,7 +3213,7 @@ function useBoardInteractions(options = {}) {
2527
3213
  return [];
2528
3214
  }
2529
3215
  if (!isInteractionAvailable(descriptor)) return [];
2530
- const draft = store.getDraft(descriptor.interactionKey);
3216
+ const draft = drafts[descriptor.interactionKey] ?? {};
2531
3217
  const inputKey = inputKeyForTarget(
2532
3218
  descriptor,
2533
3219
  targetKind,
@@ -2536,11 +3222,7 @@ function useBoardInteractions(options = {}) {
2536
3222
  );
2537
3223
  if (!inputKey) return [];
2538
3224
  const input = inputByTarget(descriptor, targetKind, targetId, draft);
2539
- if (input && !isTargetSelectable(
2540
- input,
2541
- store.getDraft(descriptor.interactionKey),
2542
- targetId
2543
- )) {
3225
+ if (input && !isTargetSelectable(input, draft, targetId)) {
2544
3226
  return [];
2545
3227
  }
2546
3228
  const targets = eligibleTargetsForInput(descriptor, inputKey, draft);
@@ -2555,7 +3237,7 @@ function useBoardInteractions(options = {}) {
2555
3237
  });
2556
3238
  return matches;
2557
3239
  },
2558
- [armedIds, interactions, store]
3240
+ [armedIds, drafts, interactions]
2559
3241
  );
2560
3242
  const selectByKind = useCallback3(
2561
3243
  async (targetKind, targetId, extraInputs, interactionKeys) => {
@@ -2605,10 +3287,18 @@ function useBoardInteractions(options = {}) {
2605
3287
  pending,
2606
3288
  conflict,
2607
3289
  conflictInteractionKeys: conflict ? candidates.map((candidate) => candidate.descriptor.interactionKey) : void 0,
2608
- unavailableReason: candidateUnavailableReason(selected, conflict)
3290
+ unavailableReason: candidateUnavailableReason(selected, conflict),
3291
+ browserAttributes: selected ? boardTargetBrowserAttributes({
3292
+ descriptor: selected.descriptor,
3293
+ inputKey: selected.inputKey,
3294
+ targetKind,
3295
+ targetId,
3296
+ enabled: eligible2 && !!controllingPlayerId,
3297
+ draft: drafts[selected.descriptor.interactionKey] ?? {}
3298
+ }) : void 0
2609
3299
  };
2610
3300
  },
2611
- [controllingPlayerId, pendingInteractionKey, resolveTargetMatches]
3301
+ [controllingPlayerId, drafts, pendingInteractionKey, resolveTargetMatches]
2612
3302
  );
2613
3303
  const targetLayers = useMemo8(() => {
2614
3304
  const createLayer = (targetKind) => (layerOptions = {}) => {
@@ -2721,6 +3411,43 @@ function isTargetSelectable(input, draft, targetId) {
2721
3411
  function missingInputsForDraft(descriptor, draft) {
2722
3412
  return [...getInteractionDraftReadiness(descriptor, draft).missingInputs];
2723
3413
  }
3414
+ var GAMEPLAY_BROWSER_SCOPE_ID2 = "runtime";
3415
+ function boardTargetBrowserAttributes({
3416
+ descriptor,
3417
+ inputKey,
3418
+ targetKind,
3419
+ targetId,
3420
+ enabled,
3421
+ draft
3422
+ }) {
3423
+ return createGameplayActuatorAttributes({
3424
+ scopeId: GAMEPLAY_BROWSER_SCOPE_ID2,
3425
+ interactionKey: descriptor.interactionKey,
3426
+ interactionId: descriptor.interactionId,
3427
+ intent: "select",
3428
+ enabled,
3429
+ actuatorKind: "click",
3430
+ actuatorId: `board:${targetKind}:${targetId}`,
3431
+ ...descriptor.descriptorDigest !== void 0 ? { descriptorDigest: descriptor.descriptorDigest } : {},
3432
+ ...descriptor.draftDigest !== void 0 ? { draftDigest: interactionDraftDigestForValues(descriptor, draft) } : {},
3433
+ inputKey,
3434
+ candidateValue: targetId,
3435
+ candidateState: isBoardTargetSelected(draft[inputKey], targetId) ? "selected" : "unselected",
3436
+ semanticEffects: gameplayCandidateMetadata({
3437
+ descriptor,
3438
+ draftValues: draft,
3439
+ inputKey,
3440
+ candidateValue: targetId,
3441
+ intent: "select"
3442
+ }).semanticEffects
3443
+ });
3444
+ }
3445
+ function isBoardTargetSelected(value, targetId) {
3446
+ if (Array.isArray(value)) {
3447
+ return value.some((item) => String(item) === targetId);
3448
+ }
3449
+ return value !== void 0 && String(value) === targetId;
3450
+ }
2724
3451
  function selectDispatchCandidate(matches, targetKind, targetId) {
2725
3452
  if (matches.length === 0) return null;
2726
3453
  const armed = matches.filter((match) => match.armed);
@@ -2743,8 +3470,8 @@ function candidateUnavailableReason(match, conflict) {
2743
3470
  return void 0;
2744
3471
  }
2745
3472
 
2746
- // src/runtime-internal/primitives/board.tsx
2747
- import { Fragment as Fragment6, jsx as jsx9 } from "react/jsx-runtime";
3473
+ // src/runtime/primitives/board.tsx
3474
+ import { Fragment as Fragment6, jsx as jsx8 } from "react/jsx-runtime";
2748
3475
  var BoardContext = createContext7(null);
2749
3476
  var warnedAmbiguousBoardTargets = /* @__PURE__ */ new Set();
2750
3477
  function warnAmbiguousBoardTarget({
@@ -2770,21 +3497,21 @@ function useBoardPrimitiveContext() {
2770
3497
  }
2771
3498
  function BoardRoot({ children, targetKinds, ...props }) {
2772
3499
  const board = useBoardInteractions({ targetKinds });
2773
- return /* @__PURE__ */ jsx9(BoardContext.Provider, { value: board, children: renderPrimitive("div", {
3500
+ return /* @__PURE__ */ jsx8(BoardContext.Provider, { value: board, children: renderPrimitive("div", {
2774
3501
  ...props,
2775
3502
  "data-dreamboard-board-root": "",
2776
3503
  children
2777
3504
  }) });
2778
3505
  }
2779
3506
  function BoardState({ children }) {
2780
- return /* @__PURE__ */ jsx9(Fragment6, { children: children(useBoardPrimitiveContext()) });
3507
+ return /* @__PURE__ */ jsx8(Fragment6, { children: children(useBoardPrimitiveContext()) });
2781
3508
  }
2782
3509
  function BoardHexView({ board, spaces, children }) {
2783
3510
  const view = useMemo9(
2784
3511
  () => createHexBoardView(board, { spaces }),
2785
3512
  [board, spaces]
2786
3513
  );
2787
- return /* @__PURE__ */ jsx9(Fragment6, { children: children(view) });
3514
+ return /* @__PURE__ */ jsx8(Fragment6, { children: children(view) });
2788
3515
  }
2789
3516
  function BoardHexGrid({
2790
3517
  board,
@@ -2809,7 +3536,7 @@ function BoardHexGrid({
2809
3536
  interactionKeys: interactions === "auto" ? void 0 : interactions.space,
2810
3537
  onError: gameActionError ?? void 0
2811
3538
  });
2812
- return /* @__PURE__ */ jsx9(BoardHexView, { board, spaces, children: (view) => /* @__PURE__ */ jsx9(
3539
+ return /* @__PURE__ */ jsx8(BoardHexView, { board, spaces, children: (view) => /* @__PURE__ */ jsx8(
2813
3540
  HexGrid,
2814
3541
  {
2815
3542
  ...props,
@@ -2831,7 +3558,7 @@ function BoardTarget({
2831
3558
  ) : void 0
2832
3559
  );
2833
3560
  if (interaction) {
2834
- return descriptor ? /* @__PURE__ */ jsx9(ExplicitBoardTarget, { descriptor, input, ...props }) : /* @__PURE__ */ jsx9(
3561
+ return descriptor ? /* @__PURE__ */ jsx8(ExplicitBoardTarget, { descriptor, input, ...props }) : /* @__PURE__ */ jsx8(
2835
3562
  UnavailableBoardTarget,
2836
3563
  {
2837
3564
  interaction,
@@ -2840,16 +3567,16 @@ function BoardTarget({
2840
3567
  }
2841
3568
  );
2842
3569
  }
2843
- return /* @__PURE__ */ jsx9(UnambiguousBoardTarget, { input, ...props });
3570
+ return /* @__PURE__ */ jsx8(UnambiguousBoardTarget, { input, ...props });
2844
3571
  }
2845
3572
  function BoardSpaceTarget(props) {
2846
- return /* @__PURE__ */ jsx9(BoardTarget, { kind: "space", ...props });
3573
+ return /* @__PURE__ */ jsx8(BoardTarget, { kind: "space", ...props });
2847
3574
  }
2848
3575
  function BoardEdgeTarget(props) {
2849
- return /* @__PURE__ */ jsx9(BoardTarget, { kind: "edge", ...props });
3576
+ return /* @__PURE__ */ jsx8(BoardTarget, { kind: "edge", ...props });
2850
3577
  }
2851
3578
  function BoardVertexTarget(props) {
2852
- return /* @__PURE__ */ jsx9(BoardTarget, { kind: "vertex", ...props });
3579
+ return /* @__PURE__ */ jsx8(BoardTarget, { kind: "vertex", ...props });
2853
3580
  }
2854
3581
  function UnambiguousBoardTarget({
2855
3582
  kind,
@@ -2882,6 +3609,7 @@ function UnambiguousBoardTarget({
2882
3609
  return renderPrimitive("button", {
2883
3610
  type: "button",
2884
3611
  ...props,
3612
+ ...targetState.browserAttributes,
2885
3613
  children,
2886
3614
  disabled: isDisabled,
2887
3615
  "aria-disabled": isDisabled,
@@ -2929,9 +3657,18 @@ function ExplicitBoardTarget({
2929
3657
  const eligibleTargets = inputKey ? eligibleTargetsForInput(descriptor, inputKey, draft) : void 0;
2930
3658
  const eligible = inputDescriptor !== void 0 && inputDescriptor.domain.type === "boardTarget" && isResolvedTargetDomain(inputDescriptor.domain) && inputDescriptor.domain.targetKind === kind && (eligibleTargets ?? inputDescriptor.domain.eligibleTargets).includes(value);
2931
3659
  const isDisabled = disabled ?? (!isInteractionAvailable(descriptor) || !eligible);
3660
+ const browserAttributes = inputKey ? boardTargetBrowserAttributes2({
3661
+ descriptor,
3662
+ inputKey,
3663
+ targetKind: kind,
3664
+ targetId: value,
3665
+ enabled: !isDisabled,
3666
+ draft
3667
+ }) : void 0;
2932
3668
  return renderPrimitive("button", {
2933
3669
  type: "button",
2934
3670
  ...props,
3671
+ ...browserAttributes,
2935
3672
  children,
2936
3673
  disabled: isDisabled,
2937
3674
  "aria-disabled": isDisabled,
@@ -2990,6 +3727,43 @@ function UnavailableBoardTarget({
2990
3727
  function resolveExtraInputs(extraInputs, targetId) {
2991
3728
  return typeof extraInputs === "function" ? extraInputs(targetId) : extraInputs ?? {};
2992
3729
  }
3730
+ var GAMEPLAY_BROWSER_SCOPE_ID3 = "runtime";
3731
+ function boardTargetBrowserAttributes2({
3732
+ descriptor,
3733
+ inputKey,
3734
+ targetKind,
3735
+ targetId,
3736
+ enabled,
3737
+ draft
3738
+ }) {
3739
+ return createGameplayActuatorAttributes({
3740
+ scopeId: GAMEPLAY_BROWSER_SCOPE_ID3,
3741
+ interactionKey: descriptor.interactionKey,
3742
+ interactionId: descriptor.interactionId,
3743
+ intent: "select",
3744
+ enabled,
3745
+ actuatorKind: "click",
3746
+ actuatorId: `board:${targetKind}:${targetId}`,
3747
+ ...descriptor.descriptorDigest !== void 0 ? { descriptorDigest: descriptor.descriptorDigest } : {},
3748
+ ...descriptor.draftDigest !== void 0 ? { draftDigest: interactionDraftDigestForValues(descriptor, draft) } : {},
3749
+ inputKey,
3750
+ candidateValue: targetId,
3751
+ candidateState: isBoardTargetSelected2(draft[inputKey], targetId) ? "selected" : "unselected",
3752
+ semanticEffects: gameplayCandidateMetadata({
3753
+ descriptor,
3754
+ draftValues: draft,
3755
+ inputKey,
3756
+ candidateValue: targetId,
3757
+ intent: "select"
3758
+ }).semanticEffects
3759
+ });
3760
+ }
3761
+ function isBoardTargetSelected2(value, targetId) {
3762
+ if (Array.isArray(value)) {
3763
+ return value.some((item) => String(item) === targetId);
3764
+ }
3765
+ return value !== void 0 && String(value) === targetId;
3766
+ }
2993
3767
  var Board = {
2994
3768
  Root: BoardRoot,
2995
3769
  State: BoardState,
@@ -3001,28 +3775,25 @@ var Board = {
3001
3775
  VertexTarget: BoardVertexTarget
3002
3776
  };
3003
3777
 
3004
- // src/runtime-internal/primitives/interaction.tsx
3778
+ // src/runtime/primitives/interaction/context.tsx
3005
3779
  import {
3006
3780
  createContext as createContext9,
3007
- useCallback as useCallback6,
3008
3781
  useContext as useContext9,
3009
- useEffect as useEffect7,
3010
- useMemo as useMemo13,
3011
- useRef as useRef4
3782
+ useMemo as useMemo11
3012
3783
  } from "react";
3013
3784
 
3014
- // src/runtime-internal/hooks/useInteractionHandle.ts
3785
+ // src/runtime/hooks/useInteractionHandle.ts
3015
3786
  import { useCallback as useCallback4, useEffect as useEffect5, useMemo as useMemo10, useRef as useRef3 } from "react";
3016
3787
 
3017
- // src/runtime-internal/context/ClientParamSchemaContext.tsx
3788
+ // src/runtime/context/ClientParamSchemaContext.tsx
3018
3789
  import { createContext as createContext8, useContext as useContext8 } from "react";
3019
- import { jsx as jsx10 } from "react/jsx-runtime";
3790
+ import { jsx as jsx9 } from "react/jsx-runtime";
3020
3791
  var ClientParamSchemaContext = createContext8({});
3021
3792
  function ClientParamSchemaProvider({
3022
3793
  schemas,
3023
3794
  children
3024
3795
  }) {
3025
- return /* @__PURE__ */ jsx10(ClientParamSchemaContext.Provider, { value: schemas ?? {}, children });
3796
+ return /* @__PURE__ */ jsx9(ClientParamSchemaContext.Provider, { value: schemas ?? {}, children });
3026
3797
  }
3027
3798
  function useClientParamSchema(phaseName, interactionId) {
3028
3799
  const schemas = useContext8(ClientParamSchemaContext);
@@ -3030,7 +3801,7 @@ function useClientParamSchema(phaseName, interactionId) {
3030
3801
  return schemas[phaseName]?.[interactionId];
3031
3802
  }
3032
3803
 
3033
- // src/runtime-internal/hooks/useInteractionHandle.ts
3804
+ // src/runtime/hooks/useInteractionHandle.ts
3034
3805
  function useInteractionHandle(descriptor) {
3035
3806
  const runtime = useRuntimeContext();
3036
3807
  const { controllingPlayerId } = usePluginSession();
@@ -3275,423 +4046,146 @@ function useInteractionHandle(descriptor) {
3275
4046
  };
3276
4047
  }
3277
4048
 
3278
- // src/runtime-internal/components/InteractionForm.tsx
3279
- import {
3280
- useEffect as useEffect6,
3281
- useId,
3282
- useMemo as useMemo11,
3283
- useState as useState4
3284
- } from "react";
3285
- import * as AccordionPrimitive from "@radix-ui/react-accordion";
3286
- import { Fragment as Fragment7, jsx as jsx11, jsxs as jsxs3 } from "react/jsx-runtime";
3287
- var EMPTY_FIELD_ERRORS = [];
3288
- function InteractionForm({
4049
+ // src/runtime/interactions/gameplay-attributes.ts
4050
+ var GAMEPLAY_BROWSER_SCOPE_ID4 = "runtime";
4051
+ function gameplayInteractionRootAttributes({
3289
4052
  descriptor,
3290
- handle,
3291
- fields,
3292
- hiddenFields,
3293
- renderFields,
3294
- inputs,
3295
- submit: renderSubmit,
3296
- title,
3297
- description,
3298
- submitLabel,
3299
- cancelLabel = "Cancel",
3300
- onCancel,
3301
- onSubmitSuccess,
3302
- disabled = false,
3303
- accordion = true,
3304
- defaultOpen = false,
3305
- style
4053
+ draftDigest: draftDigest2,
4054
+ ready,
4055
+ available
3306
4056
  }) {
3307
- const theme = useTheme();
3308
- const fallbackLabel = interactionLabel(descriptor);
3309
- const formId = useId();
3310
- useChromeSuppression(formId, true);
3311
- const [pending, setPending] = useState4(false);
3312
- const [validation, setValidation] = useState4(
3313
- null
3314
- );
3315
- const [formError, setFormError] = useState4(null);
3316
- const [accordionOpen, setAccordionOpen] = useState4(defaultOpen);
3317
- const hidden = useMemo11(() => new Set(hiddenFields ?? []), [hiddenFields]);
3318
- const visibleInputs = useMemo11(() => {
3319
- if (inputs) {
3320
- const rendered = new Set(Object.keys(inputs));
3321
- return resolveInteractionInputs(
3322
- descriptor,
3323
- handle.values
3324
- ).filter((input) => rendered.has(input.key));
3325
- }
3326
- const allowed = fields ? new Set(fields) : null;
3327
- return defaultFormInputs(
3328
- descriptor,
3329
- handle.values
3330
- ).filter((input) => {
3331
- const key = input.key;
3332
- if (allowed && !allowed.has(key)) return false;
3333
- return !hidden.has(key);
3334
- });
3335
- }, [descriptor, fields, hidden, handle.values, inputs]);
3336
- const currentValidation = validation;
3337
- const fieldErrors = currentValidation?.fieldErrors ?? {};
3338
- const missing = new Set(currentValidation?.missing ?? []);
3339
- const formErrors = [
3340
- ...currentValidation?.formErrors ?? [],
3341
- ...formError ? [formError] : []
3342
- ];
3343
- const isDisabled = disabled || pending || !isInteractionAvailable(descriptor);
3344
- const useAccordion = accordion && visibleInputs.length > 0;
3345
- useEffect6(() => {
3346
- setAccordionOpen(defaultOpen);
3347
- }, [defaultOpen, descriptor.interactionId]);
3348
- const containerStyle = {
3349
- ...surfaceStyle(theme, { tone: "card" }),
3350
- display: "flex",
3351
- flexDirection: "column",
3352
- gap: theme.space[2],
3353
- padding: theme.space[3],
3354
- minWidth: "min(100%, 280px)",
3355
- boxSizing: "border-box",
3356
- fontFamily: theme.typography.fontFamily.body,
3357
- ...style
3358
- };
3359
- const submit = async (event) => {
3360
- event.preventDefault();
3361
- if (isDisabled) return;
3362
- const nextValidation = handle.validateDraft();
3363
- setValidation(nextValidation);
3364
- setFormError(null);
3365
- if (!nextValidation.ok) {
3366
- setAccordionOpen(true);
3367
- return;
3368
- }
3369
- setPending(true);
3370
- try {
3371
- await handle.submitDraft();
3372
- onSubmitSuccess?.();
3373
- setAccordionOpen(defaultOpen);
3374
- } catch (error) {
3375
- setAccordionOpen(true);
3376
- setFormError(
3377
- error instanceof Error ? error.message : "Interaction submission failed"
3378
- );
3379
- } finally {
3380
- setPending(false);
3381
- }
3382
- };
3383
- const header = /* @__PURE__ */ jsxs3("div", { style: { display: "flex", flexDirection: "column", gap: 2 }, children: [
3384
- /* @__PURE__ */ jsx11(
3385
- "strong",
3386
- {
3387
- style: {
3388
- fontFamily: theme.typography.fontFamily.display,
3389
- fontSize: theme.typography.fontSize.md,
3390
- color: theme.semantic.text.primary
3391
- },
3392
- children: title ?? fallbackLabel
3393
- }
3394
- ),
3395
- description ? /* @__PURE__ */ jsx11(
3396
- "span",
3397
- {
3398
- style: {
3399
- fontSize: theme.typography.fontSize.sm,
3400
- color: theme.semantic.text.muted
3401
- },
3402
- children: description
3403
- }
3404
- ) : null
3405
- ] });
3406
- const fieldsContent = visibleInputs.length > 0 ? /* @__PURE__ */ jsx11(
3407
- "div",
3408
- {
3409
- style: {
3410
- display: "flex",
3411
- flexDirection: "column",
3412
- gap: theme.space[3]
3413
- },
3414
- children: visibleInputs.map((input) => {
3415
- const key = input.key;
3416
- const inputRenderer = inputs?.[key];
3417
- return /* @__PURE__ */ jsx11(
3418
- InteractionField,
3419
- {
3420
- descriptor,
3421
- inputKey: key,
3422
- handle,
3423
- errors: fieldErrors[key] ?? [],
3424
- missing: missing.has(key),
3425
- disabled: isDisabled,
3426
- render: inputRenderer ? ({ input: input2, errors, missing: missing2, disabled: disabled2 }) => inputRenderer(
3427
- createInteractionInputSlot({
3428
- descriptor,
3429
- input: input2,
3430
- handle,
3431
- errors,
3432
- missing: missing2,
3433
- disabled: disabled2
3434
- })
3435
- ) : renderFields?.[key]
3436
- },
3437
- input.key
3438
- );
3439
- })
3440
- }
3441
- ) : null;
3442
- if (visibleInputs.length === 0 && !handle.isReady) {
4057
+ return createGameplayInteractionRootAttributes({
4058
+ scopeId: GAMEPLAY_BROWSER_SCOPE_ID4,
4059
+ interactionKey: descriptor.interactionKey,
4060
+ interactionId: descriptor.interactionId,
4061
+ ...descriptor.descriptorDigest !== void 0 ? { descriptorDigest: descriptor.descriptorDigest } : {},
4062
+ ...draftDigest2 !== void 0 ? { draftDigest: draftDigest2 } : {},
4063
+ readiness: available ? ready ? "ready" : "blocked" : "unavailable"
4064
+ });
4065
+ }
4066
+ function gameplayActuatorAttributes({
4067
+ descriptor,
4068
+ draftDigest: draftDigest2,
4069
+ inputKey,
4070
+ intent,
4071
+ candidateValue,
4072
+ candidateState,
4073
+ semanticEffects,
4074
+ acceptedEffectPatterns,
4075
+ preparationPatterns,
4076
+ enabled,
4077
+ actuatorKind,
4078
+ actuatorId
4079
+ }) {
4080
+ return createGameplayActuatorAttributes({
4081
+ scopeId: GAMEPLAY_BROWSER_SCOPE_ID4,
4082
+ interactionKey: descriptor.interactionKey,
4083
+ interactionId: descriptor.interactionId,
4084
+ intent,
4085
+ enabled,
4086
+ actuatorKind,
4087
+ actuatorId,
4088
+ ...descriptor.descriptorDigest !== void 0 ? { descriptorDigest: descriptor.descriptorDigest } : {},
4089
+ ...draftDigest2 !== void 0 ? { draftDigest: draftDigest2 } : {},
4090
+ ...inputKey !== void 0 ? { inputKey } : {},
4091
+ ...candidateValue !== void 0 ? { candidateValue } : {},
4092
+ ...candidateState !== void 0 ? { candidateState } : {},
4093
+ ...semanticEffects !== void 0 ? { semanticEffects } : {},
4094
+ ...acceptedEffectPatterns !== void 0 ? { acceptedEffectPatterns } : {},
4095
+ ...preparationPatterns !== void 0 ? { preparationPatterns } : {}
4096
+ });
4097
+ }
4098
+
4099
+ // src/runtime/primitives/interaction/context.tsx
4100
+ import { jsx as jsx10 } from "react/jsx-runtime";
4101
+ var InteractionContext = createContext9(null);
4102
+ function humanizeInteraction(value) {
4103
+ const parts = value.split(".");
4104
+ const leaf = parts[parts.length - 1] ?? value;
4105
+ return leaf.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[-_]+/g, " ").replace(/\s+/g, " ").trim().replace(/^./, (first) => first.toUpperCase());
4106
+ }
4107
+ function useInteractionPrimitiveContext() {
4108
+ const value = useContext9(InteractionContext);
4109
+ if (!value) {
3443
4110
  throw new Error(
3444
- `InteractionForm '${descriptor.interactionKey}' has required inputs that cannot be rendered by the default form. Provide renderFields, select on a surface, or use a default-renderable input domain.`
4111
+ "Interaction primitives must be rendered inside <Interaction.Root>."
3445
4112
  );
3446
4113
  }
3447
- const formErrorContent = formErrors.length > 0 ? /* @__PURE__ */ jsx11(
3448
- "div",
3449
- {
3450
- role: "alert",
3451
- style: {
3452
- display: "flex",
3453
- flexDirection: "column",
3454
- gap: theme.space[1],
3455
- color: theme.semantic.intent.danger.solid,
3456
- fontSize: theme.typography.fontSize.sm
3457
- },
3458
- children: formErrors.map((error) => /* @__PURE__ */ jsx11("span", { children: error }, error))
3459
- }
3460
- ) : null;
3461
- const actions = /* @__PURE__ */ jsxs3(
3462
- "div",
3463
- {
3464
- style: {
3465
- display: "flex",
3466
- gap: theme.space[2],
3467
- justifyContent: "flex-end"
3468
- },
3469
- children: [
3470
- onCancel ? /* @__PURE__ */ jsx11(
3471
- ThemedButton,
3472
- {
3473
- type: "button",
3474
- variant: "secondary",
3475
- size: "sm",
3476
- disabled: pending,
3477
- onClick: onCancel,
3478
- className: "h-9 px-3 text-sm",
3479
- children: cancelLabel
3480
- }
3481
- ) : null,
3482
- renderSubmit ? renderSubmit(
3483
- {
3484
- Button: ({ children, ...buttonProps }) => /* @__PURE__ */ jsx11(
3485
- ThemedButton,
3486
- {
3487
- type: "submit",
3488
- variant: "primary",
3489
- size: "sm",
3490
- disabled: isDisabled,
3491
- className: "h-9 px-3 text-sm",
3492
- ...buttonProps,
3493
- children: pending ? "Submitting..." : children ?? submitLabel ?? fallbackLabel
3494
- }
3495
- )
3496
- },
3497
- descriptor
3498
- ) : /* @__PURE__ */ jsx11(
3499
- ThemedButton,
3500
- {
3501
- type: "submit",
3502
- variant: "primary",
3503
- size: "sm",
3504
- disabled: isDisabled,
3505
- className: "h-9 px-3 text-sm",
3506
- children: pending ? "Submitting..." : submitLabel ?? fallbackLabel
3507
- }
3508
- )
3509
- ]
3510
- }
4114
+ return value;
4115
+ }
4116
+ function useResolvedCardTargetValue() {
4117
+ const context = useContext9(InteractionContext);
4118
+ const descriptor = context?.descriptor;
4119
+ const handle = context?.handle;
4120
+ if (!descriptor || !handle) return void 0;
4121
+ const cardInput = descriptor.inputs.find(
4122
+ (input) => isTargetDomain(input.domain) && input.domain.type === "cardTarget"
3511
4123
  );
3512
- const body = /* @__PURE__ */ jsxs3(Fragment7, { children: [
3513
- fieldsContent,
3514
- formErrorContent,
3515
- actions
3516
- ] });
3517
- return /* @__PURE__ */ jsx11(
3518
- "form",
3519
- {
3520
- "data-interaction-form": true,
3521
- "data-interaction-id": descriptor.interactionId,
3522
- onSubmit: (event) => void submit(event),
3523
- style: containerStyle,
3524
- children: useAccordion ? /* @__PURE__ */ jsx11(
3525
- AccordionPrimitive.Root,
3526
- {
3527
- type: "single",
3528
- collapsible: true,
3529
- value: accordionOpen ? "fields" : void 0,
3530
- onValueChange: (value) => setAccordionOpen(value === "fields"),
3531
- children: /* @__PURE__ */ jsxs3(AccordionPrimitive.Item, { value: "fields", children: [
3532
- /* @__PURE__ */ jsx11(AccordionPrimitive.Header, { style: { margin: 0 }, children: /* @__PURE__ */ jsxs3(
3533
- AccordionPrimitive.Trigger,
3534
- {
3535
- style: {
3536
- alignItems: "center",
3537
- appearance: "none",
3538
- background: "transparent",
3539
- border: 0,
3540
- color: theme.semantic.text.primary,
3541
- cursor: "pointer",
3542
- display: "flex",
3543
- fontFamily: theme.typography.fontFamily.display,
3544
- fontSize: theme.typography.fontSize.md,
3545
- fontWeight: theme.typography.fontWeight.bold,
3546
- justifyContent: "space-between",
3547
- padding: 0,
3548
- textAlign: "left",
3549
- width: "100%"
3550
- },
3551
- children: [
3552
- /* @__PURE__ */ jsx11("span", { children: title ?? fallbackLabel }),
3553
- /* @__PURE__ */ jsx11("span", { "aria-hidden": true, children: accordionOpen ? "\u2212" : "+" })
3554
- ]
3555
- }
3556
- ) }),
3557
- /* @__PURE__ */ jsx11(AccordionPrimitive.Content, { children: /* @__PURE__ */ jsxs3(
3558
- "div",
3559
- {
3560
- style: {
3561
- display: "flex",
3562
- flexDirection: "column",
3563
- gap: theme.space[2],
3564
- marginTop: theme.space[2]
3565
- },
3566
- children: [
3567
- description ? /* @__PURE__ */ jsx11(
3568
- "span",
3569
- {
3570
- style: {
3571
- fontSize: theme.typography.fontSize.sm,
3572
- color: theme.semantic.text.muted
3573
- },
3574
- children: description
3575
- }
3576
- ) : null,
3577
- body
3578
- ]
3579
- }
3580
- ) })
3581
- ] })
3582
- }
3583
- ) : /* @__PURE__ */ jsxs3(Fragment7, { children: [
3584
- header,
3585
- body
3586
- ] })
3587
- }
4124
+ if (!cardInput) return void 0;
4125
+ return handle.values[cardInput.key];
4126
+ }
4127
+ function useInteractionDescriptor(interaction) {
4128
+ return usePluginState(
4129
+ (state) => state.gameplay.availableInteractions.find(
4130
+ (descriptor) => descriptor.interactionKey === interaction || descriptor.interactionId === interaction
4131
+ )
3588
4132
  );
3589
4133
  }
3590
- function createInteractionInputSlot({
4134
+ function ResolvedInteractionRoot({
4135
+ interaction,
3591
4136
  descriptor,
3592
- input,
3593
- handle,
3594
- errors,
3595
- missing,
3596
- disabled
4137
+ children
3597
4138
  }) {
3598
- const value = handle.values[input.key];
3599
- const resolvedInput = resolveInputDomain(
3600
- input,
3601
- handle.values
4139
+ const handle = useInteractionHandle(descriptor);
4140
+ const value = useMemo11(
4141
+ () => ({ interaction, descriptor, handle }),
4142
+ [descriptor, handle, interaction]
3602
4143
  );
3603
- const targetButton = ({
3604
- value: targetValue,
3605
- children,
3606
- kind,
3607
- ...buttonProps
3608
- }) => {
3609
- const domain = resolvedInput.domain;
3610
- const eligible = isResolvedTargetDomain(domain) && domain.eligibleTargets.includes(targetValue);
3611
- const selection = isTargetDomain(domain) ? domain.selection : void 0;
3612
- const currentValue = handle.values[input.key];
3613
- const selected = selection?.mode === "many" ? Array.isArray(currentValue) && currentValue.map(String).includes(targetValue) : currentValue !== void 0 && String(currentValue) === targetValue;
3614
- const isDisabled = disabled || !eligible;
3615
- const dataAttribute = kind === "card" ? { "data-dreamboard-interaction-card-slot": "" } : { "data-dreamboard-interaction-target-slot": "" };
3616
- return /* @__PURE__ */ jsx11(
3617
- "button",
4144
+ const available = isInteractionAvailable(descriptor);
4145
+ const rootAttributes = createGameplayInteractionRootAttributes({
4146
+ scopeId: GAMEPLAY_BROWSER_SCOPE_ID4,
4147
+ interactionKey: descriptor.interactionKey,
4148
+ interactionId: descriptor.interactionId,
4149
+ ...descriptor.descriptorDigest !== void 0 ? { descriptorDigest: descriptor.descriptorDigest } : {},
4150
+ ...descriptor.draftDigest !== void 0 ? { draftDigest: descriptor.draftDigest } : {},
4151
+ readiness: available ? handle.isReady ? "ready" : "blocked" : "unavailable"
4152
+ });
4153
+ return /* @__PURE__ */ jsx10(InteractionContext.Provider, { value, children: renderPrimitive("span", {
4154
+ ...rootAttributes,
4155
+ style: { display: "contents" },
4156
+ children
4157
+ }) });
4158
+ }
4159
+ function InteractionRoot({
4160
+ interaction,
4161
+ children,
4162
+ unavailable = "render"
4163
+ }) {
4164
+ const descriptor = useInteractionDescriptor(interaction);
4165
+ if (!descriptor) {
4166
+ if (unavailable === "hide") return null;
4167
+ return /* @__PURE__ */ jsx10(
4168
+ InteractionContext.Provider,
3618
4169
  {
3619
- type: "button",
3620
- disabled: isDisabled,
3621
- "aria-disabled": isDisabled,
3622
- "aria-pressed": selected,
3623
- "data-input-name": input.key,
3624
- "data-target-kind": inputTargetKind(domain),
3625
- "data-target-value": targetValue,
3626
- "data-eligible": eligible,
3627
- "data-selected": selected || void 0,
3628
- "data-disabled": isDisabled || void 0,
3629
- ...dataAttribute,
3630
- ...buttonProps,
3631
- onClick: () => {
3632
- if (isDisabled) return;
3633
- const nextValue = selection?.mode === "many" ? toggleManyValue(currentValue, targetValue, selection) : targetValue;
3634
- handle.setInput(input.key, nextValue);
4170
+ value: {
4171
+ interaction,
4172
+ descriptor: null,
4173
+ handle: null
3635
4174
  },
3636
- children: children ?? targetValue
4175
+ children
3637
4176
  }
3638
4177
  );
3639
- };
3640
- return {
3641
- Field: () => /* @__PURE__ */ jsx11(
3642
- DefaultInteractionField,
3643
- {
3644
- descriptor,
3645
- input: resolvedInput,
3646
- handle,
3647
- value,
3648
- setValue: (next) => handle.setInput(input.key, next),
3649
- clearValue: () => handle.clearInput(input.key),
3650
- errors,
3651
- missing,
3652
- disabled
3653
- }
3654
- ),
3655
- Default: ({ children }) => {
3656
- const hasDefault = "defaultValue" in input;
3657
- const isDisabled = disabled || !hasDefault;
3658
- return /* @__PURE__ */ jsx11(
3659
- "button",
3660
- {
3661
- type: "button",
3662
- disabled: isDisabled,
3663
- "aria-disabled": isDisabled,
3664
- "data-dreamboard-interaction-default-slot": "",
3665
- "data-input-name": input.key,
3666
- "data-disabled": isDisabled || void 0,
3667
- onClick: () => {
3668
- if (isDisabled) return;
3669
- handle.setInput(input.key, input.defaultValue);
3670
- },
3671
- children: children ?? "Use default"
3672
- }
3673
- );
3674
- },
3675
- Target: (props) => targetButton({ ...props, kind: "target" }),
3676
- Card: (props) => targetButton({ ...props, kind: "card" }),
3677
- Cards: ({ children }) => {
3678
- const domain = resolvedInput.domain;
3679
- const targets = isResolvedTargetDomain(domain) ? domain.eligibleTargets : [];
3680
- return /* @__PURE__ */ jsx11(Fragment7, { children: targets.map((id) => children({ id })) });
3681
- },
3682
- Options: ({ children }) => {
3683
- const domain = resolvedInput.domain;
3684
- const choices = domain.type === "choice" || domain.type === "choiceList" ? domain.choices ?? [] : [];
3685
- return /* @__PURE__ */ jsx11(Fragment7, { children: choices.map((choice) => children(choice)) });
3686
- },
3687
- Value: ({ children }) => /* @__PURE__ */ jsx11(Fragment7, { children: children(value) }),
3688
- Label: ({ children }) => /* @__PURE__ */ jsx11(Fragment7, { children: children ?? labelForInput(resolvedInput) }),
3689
- Message: ({ children }) => {
3690
- const message = children ?? errors[0] ?? (missing ? "Required" : null);
3691
- return message ? /* @__PURE__ */ jsx11("span", { role: "alert", "data-dreamboard-interaction-message-slot": "", children: message }) : null;
3692
- }
3693
- };
4178
+ }
4179
+ if (!isInteractionAvailable(descriptor) && unavailable === "hide") {
4180
+ return null;
4181
+ }
4182
+ return /* @__PURE__ */ jsx10(ResolvedInteractionRoot, { interaction, descriptor, children });
3694
4183
  }
4184
+
4185
+ // src/runtime/components/interaction-form/fields.tsx
4186
+ import { useId } from "react";
4187
+ import { Fragment as Fragment7, jsx as jsx11, jsxs as jsxs3 } from "react/jsx-runtime";
4188
+ var EMPTY_FIELD_ERRORS = [];
3695
4189
  function InteractionField({
3696
4190
  descriptor,
3697
4191
  inputKey,
@@ -3755,144 +4249,526 @@ function DefaultInteractionField(props) {
3755
4249
  selection: input.domain.selection
3756
4250
  }
3757
4251
  }
3758
- );
4252
+ );
4253
+ }
4254
+ return /* @__PURE__ */ jsx11(ChoiceField, { ...props, domain: input.domain });
4255
+ case "choiceList":
4256
+ return /* @__PURE__ */ jsx11(ChoiceListField, { ...props, domain: input.domain });
4257
+ case "resourceMap":
4258
+ return /* @__PURE__ */ jsx11(ResourceMapField, { ...props, domain: input.domain });
4259
+ case "boundedNumber":
4260
+ return /* @__PURE__ */ jsx11(BoundedNumberField, { ...props, domain: input.domain });
4261
+ case "cardTarget":
4262
+ case "boardTarget":
4263
+ return /* @__PURE__ */ jsx11(TargetSummaryField, { ...props, domain: input.domain });
4264
+ }
4265
+ }
4266
+ function FieldFrame({
4267
+ label,
4268
+ controlId,
4269
+ errors,
4270
+ missing,
4271
+ children
4272
+ }) {
4273
+ const theme = useTheme();
4274
+ const messages = errors.length > 0 ? errors : missing ? ["Required"] : [];
4275
+ return /* @__PURE__ */ jsxs3(
4276
+ "div",
4277
+ {
4278
+ style: {
4279
+ display: "flex",
4280
+ flexDirection: "column",
4281
+ gap: theme.space[1],
4282
+ fontSize: theme.typography.fontSize.sm,
4283
+ color: theme.semantic.text.primary
4284
+ },
4285
+ children: [
4286
+ /* @__PURE__ */ jsx11(
4287
+ Label,
4288
+ {
4289
+ htmlFor: controlId,
4290
+ style: {
4291
+ color: theme.semantic.text.primary,
4292
+ fontWeight: theme.typography.fontWeight.bold
4293
+ },
4294
+ children: label
4295
+ }
4296
+ ),
4297
+ children,
4298
+ messages.length > 0 ? /* @__PURE__ */ jsx11(
4299
+ "span",
4300
+ {
4301
+ role: "alert",
4302
+ style: {
4303
+ display: "flex",
4304
+ flexDirection: "column",
4305
+ gap: 2,
4306
+ color: theme.semantic.intent.danger.solid,
4307
+ fontSize: theme.typography.fontSize.xs
4308
+ },
4309
+ children: messages.map((message) => /* @__PURE__ */ jsx11("span", { children: message }, message))
4310
+ }
4311
+ ) : null
4312
+ ]
4313
+ }
4314
+ );
4315
+ }
4316
+ function ChoiceOptionLabel({ choice }) {
4317
+ const theme = useTheme();
4318
+ return /* @__PURE__ */ jsxs3(
4319
+ "span",
4320
+ {
4321
+ style: {
4322
+ display: "inline-flex",
4323
+ alignItems: "center",
4324
+ gap: 6,
4325
+ minWidth: 0
4326
+ },
4327
+ children: [
4328
+ /* @__PURE__ */ jsxs3(
4329
+ "span",
4330
+ {
4331
+ style: {
4332
+ display: "inline-flex",
4333
+ alignItems: "center",
4334
+ gap: 6,
4335
+ minWidth: 0
4336
+ },
4337
+ children: [
4338
+ choice.icon ? /* @__PURE__ */ jsx11("span", { "aria-hidden": true, style: { fontSize: "1.1em", lineHeight: 1 }, children: choice.icon }) : null,
4339
+ /* @__PURE__ */ jsx11("span", { style: { overflow: "hidden", textOverflow: "ellipsis" }, children: choice.label })
4340
+ ]
4341
+ }
4342
+ ),
4343
+ choice.badge ? /* @__PURE__ */ jsx11(
4344
+ "span",
4345
+ {
4346
+ style: {
4347
+ borderRadius: 999,
4348
+ background: theme.semantic.surface.inset,
4349
+ color: theme.semantic.text.muted,
4350
+ fontSize: theme.typography.fontSize.xs,
4351
+ fontWeight: theme.typography.fontWeight.bold,
4352
+ lineHeight: 1,
4353
+ padding: "3px 6px",
4354
+ whiteSpace: "nowrap"
4355
+ },
4356
+ children: choice.badge
4357
+ }
4358
+ ) : null
4359
+ ]
4360
+ }
4361
+ );
4362
+ }
4363
+ function ChoiceDescription({ choice }) {
4364
+ const theme = useTheme();
4365
+ const message = choice?.disabledReason ?? choice?.description;
4366
+ if (!message) return null;
4367
+ return /* @__PURE__ */ jsx11(
4368
+ "span",
4369
+ {
4370
+ style: {
4371
+ color: choice?.disabledReason ? theme.semantic.intent.danger.solid : theme.semantic.text.muted,
4372
+ fontSize: theme.typography.fontSize.xs
4373
+ },
4374
+ children: message
4375
+ }
4376
+ );
4377
+ }
4378
+ var NULL_CHOICE_SELECT_VALUE = "__dreamboard_null_choice__";
4379
+ function choiceRenderKey(choice) {
4380
+ return choice.value === null ? NULL_CHOICE_SELECT_VALUE : choice.value;
4381
+ }
4382
+ function encodeChoiceSelectValue(value) {
4383
+ if (value === null) return NULL_CHOICE_SELECT_VALUE;
4384
+ return typeof value === "string" ? value : void 0;
4385
+ }
4386
+ function decodeChoiceSelectValue(value) {
4387
+ return value === NULL_CHOICE_SELECT_VALUE ? null : value;
4388
+ }
4389
+ function ChoiceField({
4390
+ descriptor,
4391
+ handle,
4392
+ input,
4393
+ value,
4394
+ setValue,
4395
+ errors,
4396
+ missing,
4397
+ disabled,
4398
+ domain
4399
+ }) {
4400
+ const theme = useTheme();
4401
+ const themeCssVars = useThemeCssVars();
4402
+ const choices = domain.choices ?? [];
4403
+ const controlId = useId();
4404
+ const selectedChoice = typeof value === "string" || value === null ? choices.find((choice) => choice.value === value) : void 0;
4405
+ if (choices.length > 0 && choices.length <= 3) {
4406
+ return /* @__PURE__ */ jsx11(
4407
+ FieldFrame,
4408
+ {
4409
+ label: labelForInput(input),
4410
+ errors,
4411
+ missing,
4412
+ children: /* @__PURE__ */ jsx11(
4413
+ "span",
4414
+ {
4415
+ style: {
4416
+ display: "inline-flex",
4417
+ flexWrap: "wrap",
4418
+ gap: theme.space[1]
4419
+ },
4420
+ children: choices.map((choice) => {
4421
+ const selected = value === choice.value;
4422
+ const isDisabled = disabled || choice.disabled;
4423
+ return /* @__PURE__ */ jsx11(
4424
+ ThemedButton,
4425
+ {
4426
+ type: "button",
4427
+ variant: selected ? "primary" : "secondary",
4428
+ size: "sm",
4429
+ disabled: isDisabled,
4430
+ "aria-pressed": selected,
4431
+ title: choice.disabledReason ?? choice.description,
4432
+ ...gameplayActuatorAttributes({
4433
+ descriptor,
4434
+ draftDigest: interactionDraftDigestForValues(
4435
+ descriptor,
4436
+ handle.values
4437
+ ),
4438
+ inputKey: input.key,
4439
+ intent: "select",
4440
+ candidateValue: choice.value,
4441
+ candidateState: selected ? "selected" : "unselected",
4442
+ enabled: !isDisabled,
4443
+ actuatorKind: "click",
4444
+ actuatorId: `choice:${input.key}:${choiceRenderKey(choice)}`,
4445
+ semanticEffects: gameplayCandidateMetadata({
4446
+ descriptor,
4447
+ draftValues: handle.values,
4448
+ inputKey: input.key,
4449
+ candidateValue: choice.value,
4450
+ intent: "select"
4451
+ }).semanticEffects
4452
+ }),
4453
+ onClick: () => setValue(choice.value),
4454
+ className: "h-8 px-3 text-sm",
4455
+ children: /* @__PURE__ */ jsx11(ChoiceOptionLabel, { choice })
4456
+ },
4457
+ choiceRenderKey(choice)
4458
+ );
4459
+ })
4460
+ }
4461
+ )
3759
4462
  }
3760
- return /* @__PURE__ */ jsx11(ChoiceField, { ...props, domain: input.domain });
3761
- case "choiceList":
3762
- return /* @__PURE__ */ jsx11(ChoiceListField, { ...props, domain: input.domain });
3763
- case "resourceMap":
3764
- return /* @__PURE__ */ jsx11(ResourceMapField, { ...props, domain: input.domain });
3765
- case "boundedNumber":
3766
- return /* @__PURE__ */ jsx11(BoundedNumberField, { ...props, domain: input.domain });
3767
- case "cardTarget":
3768
- case "boardTarget":
3769
- return /* @__PURE__ */ jsx11(TargetSummaryField, { ...props, domain: input.domain });
4463
+ );
3770
4464
  }
3771
- }
3772
- function FieldFrame({
3773
- label,
3774
- controlId,
3775
- errors,
3776
- missing,
3777
- children
3778
- }) {
3779
- const theme = useTheme();
3780
- const messages = errors.length > 0 ? errors : missing ? ["Required"] : [];
3781
4465
  return /* @__PURE__ */ jsxs3(
3782
- "div",
4466
+ FieldFrame,
3783
4467
  {
3784
- style: {
3785
- display: "flex",
3786
- flexDirection: "column",
3787
- gap: theme.space[1],
3788
- fontSize: theme.typography.fontSize.sm,
3789
- color: theme.semantic.text.primary
3790
- },
4468
+ label: labelForInput(input),
4469
+ controlId,
4470
+ errors,
4471
+ missing,
3791
4472
  children: [
3792
- /* @__PURE__ */ jsx11(
3793
- Label,
4473
+ /* @__PURE__ */ jsxs3(
4474
+ Select,
3794
4475
  {
3795
- htmlFor: controlId,
3796
- style: {
3797
- color: theme.semantic.text.primary,
3798
- fontWeight: theme.typography.fontWeight.bold
3799
- },
3800
- children: label
4476
+ disabled,
4477
+ value: encodeChoiceSelectValue(value),
4478
+ onValueChange: (next) => setValue(decodeChoiceSelectValue(next)),
4479
+ children: [
4480
+ /* @__PURE__ */ jsx11(
4481
+ SelectTrigger,
4482
+ {
4483
+ id: controlId,
4484
+ size: "sm",
4485
+ className: "w-full bg-white",
4486
+ ...gameplayActuatorAttributes({
4487
+ descriptor,
4488
+ draftDigest: interactionDraftDigestForValues(
4489
+ descriptor,
4490
+ handle.values
4491
+ ),
4492
+ inputKey: input.key,
4493
+ intent: "reveal",
4494
+ enabled: !disabled,
4495
+ actuatorKind: "click",
4496
+ actuatorId: `choice-reveal:${input.key}`,
4497
+ preparationPatterns: gameplayPreparationPatternsForDescriptor(
4498
+ { inputs: [input] },
4499
+ handle.values
4500
+ )
4501
+ }),
4502
+ children: /* @__PURE__ */ jsx11("span", { "data-slot": "select-value", children: selectedChoice ? /* @__PURE__ */ jsx11(ChoiceOptionLabel, { choice: selectedChoice }) : /* @__PURE__ */ jsx11("span", { style: { color: theme.semantic.text.muted }, children: "Choose..." }) })
4503
+ }
4504
+ ),
4505
+ /* @__PURE__ */ jsx11(
4506
+ SelectContent,
4507
+ {
4508
+ style: {
4509
+ ...themeCssVars,
4510
+ fontFamily: theme.typography.fontFamily.body
4511
+ },
4512
+ children: choices.map((choice) => /* @__PURE__ */ jsx11(
4513
+ SelectItem,
4514
+ {
4515
+ value: choiceRenderKey(choice),
4516
+ textValue: choice.label,
4517
+ disabled: choice.disabled,
4518
+ ...gameplayActuatorAttributes({
4519
+ descriptor,
4520
+ draftDigest: interactionDraftDigestForValues(
4521
+ descriptor,
4522
+ handle.values
4523
+ ),
4524
+ inputKey: input.key,
4525
+ intent: "select",
4526
+ candidateValue: choice.value,
4527
+ candidateState: value === choice.value ? "selected" : "unselected",
4528
+ enabled: !disabled && !choice.disabled,
4529
+ actuatorKind: "click",
4530
+ actuatorId: `choice:${input.key}:${choiceRenderKey(choice)}`,
4531
+ semanticEffects: gameplayCandidateMetadata({
4532
+ descriptor,
4533
+ draftValues: handle.values,
4534
+ inputKey: input.key,
4535
+ candidateValue: choice.value,
4536
+ intent: "select"
4537
+ }).semanticEffects
4538
+ }),
4539
+ children: /* @__PURE__ */ jsx11(ChoiceOptionLabel, { choice })
4540
+ },
4541
+ choiceRenderKey(choice)
4542
+ ))
4543
+ }
4544
+ )
4545
+ ]
3801
4546
  }
3802
4547
  ),
3803
- children,
3804
- messages.length > 0 ? /* @__PURE__ */ jsx11(
3805
- "span",
3806
- {
3807
- role: "alert",
3808
- style: {
3809
- display: "flex",
3810
- flexDirection: "column",
3811
- gap: 2,
3812
- color: theme.semantic.intent.danger.solid,
3813
- fontSize: theme.typography.fontSize.xs
3814
- },
3815
- children: messages.map((message) => /* @__PURE__ */ jsx11("span", { children: message }, message))
3816
- }
3817
- ) : null
4548
+ /* @__PURE__ */ jsx11(ChoiceDescription, { choice: selectedChoice })
3818
4549
  ]
3819
4550
  }
3820
4551
  );
3821
4552
  }
3822
- function ChoiceOptionLabel({ choice }) {
4553
+ function ChoiceListField({
4554
+ descriptor,
4555
+ handle,
4556
+ input,
4557
+ value,
4558
+ setValue,
4559
+ errors,
4560
+ missing,
4561
+ disabled,
4562
+ domain
4563
+ }) {
3823
4564
  const theme = useTheme();
3824
- return /* @__PURE__ */ jsxs3(
4565
+ const selected = new Set(Array.isArray(value) ? value : []);
4566
+ const min = domain.selection?.mode === "many" ? domain.selection.min ?? 0 : domain.min;
4567
+ const max = (domain.selection?.mode === "many" ? domain.selection.max : domain.max) ?? domain.choices?.length ?? Number.POSITIVE_INFINITY;
4568
+ const toggle = (choice) => {
4569
+ const next = new Set(selected);
4570
+ if (next.has(choice)) next.delete(choice);
4571
+ else if (next.size < max) next.add(choice);
4572
+ setValue([...next]);
4573
+ };
4574
+ const meta = min || Number.isFinite(max) ? `Pick ${min ?? 0}${Number.isFinite(max) ? `-${max}` : "+"}` : void 0;
4575
+ return /* @__PURE__ */ jsx11(
4576
+ FieldFrame,
4577
+ {
4578
+ label: /* @__PURE__ */ jsxs3(
4579
+ "span",
4580
+ {
4581
+ style: {
4582
+ display: "flex",
4583
+ justifyContent: "space-between",
4584
+ gap: theme.space[2]
4585
+ },
4586
+ children: [
4587
+ /* @__PURE__ */ jsx11("span", { children: labelForInput(input) }),
4588
+ meta ? /* @__PURE__ */ jsx11("span", { style: { color: theme.semantic.text.muted }, children: meta }) : null
4589
+ ]
4590
+ }
4591
+ ),
4592
+ errors,
4593
+ missing,
4594
+ children: /* @__PURE__ */ jsx11("span", { style: { display: "flex", flexWrap: "wrap", gap: theme.space[1] }, children: (domain.choices ?? []).map((choice) => {
4595
+ const value2 = choice.value;
4596
+ const checked = selected.has(value2);
4597
+ const isDisabled = disabled || choice.disabled || !checked && selected.size >= max;
4598
+ return /* @__PURE__ */ jsx11(
4599
+ ThemedButton,
4600
+ {
4601
+ type: "button",
4602
+ variant: checked ? "primary" : "secondary",
4603
+ size: "sm",
4604
+ disabled: isDisabled,
4605
+ "aria-pressed": checked,
4606
+ title: choice.disabledReason ?? choice.description,
4607
+ ...gameplayActuatorAttributes({
4608
+ descriptor,
4609
+ draftDigest: interactionDraftDigestForValues(
4610
+ descriptor,
4611
+ handle.values
4612
+ ),
4613
+ inputKey: input.key,
4614
+ intent: "toggle",
4615
+ candidateValue: value2,
4616
+ candidateState: checked ? "selected" : "unselected",
4617
+ enabled: !isDisabled,
4618
+ actuatorKind: "click",
4619
+ actuatorId: `choice-list:${input.key}:${value2}`,
4620
+ semanticEffects: gameplayCandidateMetadata({
4621
+ descriptor,
4622
+ draftValues: handle.values,
4623
+ inputKey: input.key,
4624
+ candidateValue: value2,
4625
+ intent: "toggle"
4626
+ }).semanticEffects
4627
+ }),
4628
+ onClick: () => toggle(value2),
4629
+ className: "h-8 px-3 text-sm",
4630
+ children: /* @__PURE__ */ jsx11(ChoiceOptionLabel, { choice })
4631
+ },
4632
+ value2
4633
+ );
4634
+ }) })
4635
+ }
4636
+ );
4637
+ }
4638
+ function ResourceMapField({
4639
+ descriptor,
4640
+ handle,
4641
+ input,
4642
+ value,
4643
+ setValue,
4644
+ errors,
4645
+ missing,
4646
+ disabled,
4647
+ domain
4648
+ }) {
4649
+ const theme = useTheme();
4650
+ const current = isRecord2(value) ? value : {};
4651
+ const update = (resourceId, delta, min, max) => {
4652
+ const previous = numberOrZero(current[resourceId]);
4653
+ const next = Math.max(min, Math.min(max, previous + delta));
4654
+ setValue({ ...current, [resourceId]: next });
4655
+ };
4656
+ return /* @__PURE__ */ jsx11(FieldFrame, { label: labelForInput(input), errors, missing, children: /* @__PURE__ */ jsx11(
3825
4657
  "span",
3826
4658
  {
3827
4659
  style: {
3828
- display: "inline-flex",
3829
- alignItems: "center",
3830
- gap: 6,
3831
- minWidth: 0
4660
+ display: "grid",
4661
+ gridTemplateColumns: "repeat(auto-fit, minmax(140px, 1fr))",
4662
+ gap: theme.space[2]
3832
4663
  },
3833
- children: [
3834
- /* @__PURE__ */ jsxs3(
4664
+ children: (domain.resources ?? []).map((resource) => {
4665
+ const min = resource.min ?? 0;
4666
+ const max = resource.max ?? 0;
4667
+ const amount = numberOrZero(current[resource.resourceId]);
4668
+ return /* @__PURE__ */ jsxs3(
3835
4669
  "span",
3836
4670
  {
3837
4671
  style: {
3838
- display: "inline-flex",
4672
+ display: "grid",
4673
+ gridTemplateColumns: "minmax(0, 1fr) auto auto auto",
3839
4674
  alignItems: "center",
3840
- gap: 6,
3841
- minWidth: 0
4675
+ gap: theme.space[1],
4676
+ padding: theme.space[2],
4677
+ borderRadius: theme.radius.md,
4678
+ background: theme.semantic.surface.inset
3842
4679
  },
3843
4680
  children: [
3844
- choice.icon ? /* @__PURE__ */ jsx11("span", { "aria-hidden": true, style: { fontSize: "1.1em", lineHeight: 1 }, children: choice.icon }) : null,
3845
- /* @__PURE__ */ jsx11("span", { style: { overflow: "hidden", textOverflow: "ellipsis" }, children: choice.label })
4681
+ /* @__PURE__ */ jsxs3(
4682
+ "span",
4683
+ {
4684
+ style: {
4685
+ minWidth: 0,
4686
+ display: "inline-flex",
4687
+ alignItems: "center",
4688
+ gap: theme.space[1]
4689
+ },
4690
+ children: [
4691
+ resource.icon ? /* @__PURE__ */ jsx11("span", { "aria-hidden": true, style: { fontSize: "1.1em" }, children: resource.icon }) : null,
4692
+ resource.label ?? humanize(input.key)
4693
+ ]
4694
+ }
4695
+ ),
4696
+ /* @__PURE__ */ jsx11(
4697
+ StepperButton,
4698
+ {
4699
+ label: `Decrease ${resource.label ?? resource.resourceId}`,
4700
+ disabled: disabled || amount <= min,
4701
+ browserAttributes: gameplayActuatorAttributes({
4702
+ descriptor,
4703
+ draftDigest: interactionDraftDigestForValues(
4704
+ descriptor,
4705
+ handle.values
4706
+ ),
4707
+ inputKey: input.key,
4708
+ intent: "decrement",
4709
+ candidateValue: resource.resourceId,
4710
+ enabled: !(disabled || amount <= min),
4711
+ actuatorKind: "click",
4712
+ actuatorId: `resource-decrement:${input.key}:${resource.resourceId}`,
4713
+ semanticEffects: gameplayResourceMetadata({
4714
+ inputKey: input.key,
4715
+ resourceKey: resource.resourceId,
4716
+ delta: -1
4717
+ }).semanticEffects
4718
+ }),
4719
+ onClick: () => update(resource.resourceId, -1, min, max),
4720
+ children: "-"
4721
+ }
4722
+ ),
4723
+ /* @__PURE__ */ jsx11(
4724
+ "span",
4725
+ {
4726
+ style: {
4727
+ minWidth: "2ch",
4728
+ textAlign: "center",
4729
+ fontVariantNumeric: "tabular-nums"
4730
+ },
4731
+ children: amount
4732
+ }
4733
+ ),
4734
+ /* @__PURE__ */ jsx11(
4735
+ StepperButton,
4736
+ {
4737
+ label: `Increase ${resource.label ?? resource.resourceId}`,
4738
+ disabled: disabled || amount >= max,
4739
+ browserAttributes: gameplayActuatorAttributes({
4740
+ descriptor,
4741
+ draftDigest: interactionDraftDigestForValues(
4742
+ descriptor,
4743
+ handle.values
4744
+ ),
4745
+ inputKey: input.key,
4746
+ intent: "increment",
4747
+ candidateValue: resource.resourceId,
4748
+ enabled: !(disabled || amount >= max),
4749
+ actuatorKind: "click",
4750
+ actuatorId: `resource-increment:${input.key}:${resource.resourceId}`,
4751
+ semanticEffects: gameplayResourceMetadata({
4752
+ inputKey: input.key,
4753
+ resourceKey: resource.resourceId,
4754
+ delta: 1
4755
+ }).semanticEffects
4756
+ }),
4757
+ onClick: () => update(resource.resourceId, 1, min, max),
4758
+ children: "+"
4759
+ }
4760
+ )
3846
4761
  ]
3847
- }
3848
- ),
3849
- choice.badge ? /* @__PURE__ */ jsx11(
3850
- "span",
3851
- {
3852
- style: {
3853
- borderRadius: 999,
3854
- background: theme.semantic.surface.inset,
3855
- color: theme.semantic.text.muted,
3856
- fontSize: theme.typography.fontSize.xs,
3857
- fontWeight: theme.typography.fontWeight.bold,
3858
- lineHeight: 1,
3859
- padding: "3px 6px",
3860
- whiteSpace: "nowrap"
3861
- },
3862
- children: choice.badge
3863
- }
3864
- ) : null
3865
- ]
3866
- }
3867
- );
3868
- }
3869
- function ChoiceDescription({ choice }) {
3870
- const theme = useTheme();
3871
- const message = choice?.disabledReason ?? choice?.description;
3872
- if (!message) return null;
3873
- return /* @__PURE__ */ jsx11(
3874
- "span",
3875
- {
3876
- style: {
3877
- color: choice?.disabledReason ? theme.semantic.intent.danger.solid : theme.semantic.text.muted,
3878
- fontSize: theme.typography.fontSize.xs
3879
- },
3880
- children: message
4762
+ },
4763
+ resource.resourceId
4764
+ );
4765
+ })
3881
4766
  }
3882
- );
3883
- }
3884
- var NULL_CHOICE_SELECT_VALUE = "__dreamboard_null_choice__";
3885
- function choiceRenderKey(choice) {
3886
- return choice.value === null ? NULL_CHOICE_SELECT_VALUE : choice.value;
3887
- }
3888
- function encodeChoiceSelectValue(value) {
3889
- if (value === null) return NULL_CHOICE_SELECT_VALUE;
3890
- return typeof value === "string" ? value : void 0;
3891
- }
3892
- function decodeChoiceSelectValue(value) {
3893
- return value === NULL_CHOICE_SELECT_VALUE ? null : value;
4767
+ ) });
3894
4768
  }
3895
- function ChoiceField({
4769
+ function BoundedNumberField({
4770
+ descriptor,
4771
+ handle,
3896
4772
  input,
3897
4773
  value,
3898
4774
  setValue,
@@ -3902,376 +4778,684 @@ function ChoiceField({
3902
4778
  domain
3903
4779
  }) {
3904
4780
  const theme = useTheme();
3905
- const themeCssVars = useThemeCssVars();
3906
- const choices = domain.choices ?? [];
4781
+ const min = domain.min ?? 0;
4782
+ const max = domain.max ?? Number.POSITIVE_INFINITY;
4783
+ const step = domain.step ?? 1;
4784
+ const current = typeof value === "number" ? value : min;
3907
4785
  const controlId = useId();
3908
- const selectedChoice = typeof value === "string" || value === null ? choices.find((choice) => choice.value === value) : void 0;
3909
- if (choices.length > 0 && choices.length <= 3) {
3910
- return /* @__PURE__ */ jsx11(
3911
- FieldFrame,
3912
- {
3913
- label: labelForInput(input),
3914
- errors,
3915
- missing,
3916
- children: /* @__PURE__ */ jsx11(
3917
- "span",
3918
- {
3919
- style: {
3920
- display: "inline-flex",
3921
- flexWrap: "wrap",
3922
- gap: theme.space[1]
3923
- },
3924
- children: choices.map((choice) => {
3925
- const selected = value === choice.value;
3926
- return /* @__PURE__ */ jsx11(
3927
- ThemedButton,
3928
- {
3929
- type: "button",
3930
- variant: selected ? "primary" : "secondary",
3931
- size: "sm",
3932
- disabled: disabled || choice.disabled,
3933
- "aria-pressed": selected,
3934
- title: choice.disabledReason ?? choice.description,
3935
- onClick: () => setValue(choice.value),
3936
- className: "h-8 px-3 text-sm",
3937
- children: /* @__PURE__ */ jsx11(ChoiceOptionLabel, { choice })
3938
- },
3939
- choiceRenderKey(choice)
3940
- );
3941
- })
3942
- }
3943
- )
3944
- }
3945
- );
3946
- }
3947
- return /* @__PURE__ */ jsxs3(
4786
+ const update = (next) => setValue(Math.max(min, Math.min(max, next)));
4787
+ return /* @__PURE__ */ jsx11(
3948
4788
  FieldFrame,
3949
4789
  {
3950
4790
  label: labelForInput(input),
3951
4791
  controlId,
3952
4792
  errors,
3953
4793
  missing,
3954
- children: [
3955
- /* @__PURE__ */ jsxs3(
3956
- Select,
3957
- {
3958
- disabled,
3959
- value: encodeChoiceSelectValue(value),
3960
- onValueChange: (next) => setValue(decodeChoiceSelectValue(next)),
3961
- children: [
3962
- /* @__PURE__ */ jsx11(SelectTrigger, { id: controlId, size: "sm", className: "w-full bg-white", children: /* @__PURE__ */ jsx11("span", { "data-slot": "select-value", children: selectedChoice ? /* @__PURE__ */ jsx11(ChoiceOptionLabel, { choice: selectedChoice }) : /* @__PURE__ */ jsx11("span", { style: { color: theme.semantic.text.muted }, children: "Choose..." }) }) }),
3963
- /* @__PURE__ */ jsx11(
3964
- SelectContent,
3965
- {
3966
- style: {
3967
- ...themeCssVars,
3968
- fontFamily: theme.typography.fontFamily.body
3969
- },
3970
- children: choices.map((choice) => /* @__PURE__ */ jsx11(
3971
- SelectItem,
3972
- {
3973
- value: choiceRenderKey(choice),
3974
- textValue: choice.label,
3975
- disabled: choice.disabled,
3976
- children: /* @__PURE__ */ jsx11(ChoiceOptionLabel, { choice })
3977
- },
3978
- choiceRenderKey(choice)
3979
- ))
3980
- }
3981
- )
3982
- ]
3983
- }
3984
- ),
3985
- /* @__PURE__ */ jsx11(ChoiceDescription, { choice: selectedChoice })
3986
- ]
4794
+ children: /* @__PURE__ */ jsxs3(
4795
+ "span",
4796
+ {
4797
+ style: {
4798
+ display: "inline-flex",
4799
+ alignItems: "center",
4800
+ gap: theme.space[1]
4801
+ },
4802
+ children: [
4803
+ /* @__PURE__ */ jsx11(
4804
+ StepperButton,
4805
+ {
4806
+ label: `Decrease ${input.key}`,
4807
+ disabled: disabled || current <= min,
4808
+ browserAttributes: gameplayActuatorAttributes({
4809
+ descriptor,
4810
+ draftDigest: interactionDraftDigestForValues(
4811
+ descriptor,
4812
+ handle.values
4813
+ ),
4814
+ inputKey: input.key,
4815
+ intent: "decrement",
4816
+ enabled: !(disabled || current <= min),
4817
+ actuatorKind: "click",
4818
+ actuatorId: `bounded-decrement:${input.key}`,
4819
+ semanticEffects: gameplayScalarStepMetadata({
4820
+ inputKey: input.key,
4821
+ value: Math.max(min, Math.min(max, current - step))
4822
+ }).semanticEffects
4823
+ }),
4824
+ onClick: () => update(current - step),
4825
+ children: "-"
4826
+ }
4827
+ ),
4828
+ /* @__PURE__ */ jsx11(
4829
+ Input,
4830
+ {
4831
+ id: controlId,
4832
+ type: "number",
4833
+ min,
4834
+ max: Number.isFinite(max) ? max : void 0,
4835
+ step,
4836
+ value: current,
4837
+ disabled,
4838
+ ...gameplayActuatorAttributes({
4839
+ descriptor,
4840
+ draftDigest: interactionDraftDigestForValues(
4841
+ descriptor,
4842
+ handle.values
4843
+ ),
4844
+ inputKey: input.key,
4845
+ intent: "fill",
4846
+ enabled: !disabled,
4847
+ actuatorKind: "fill",
4848
+ actuatorId: `bounded-fill:${input.key}`,
4849
+ acceptedEffectPatterns: gameplayScalarFillMetadata({
4850
+ inputKey: input.key,
4851
+ domain
4852
+ }).acceptedEffectPatterns
4853
+ }),
4854
+ onChange: (event) => update(Number(event.target.value)),
4855
+ className: "h-9 w-[8ch] px-2 text-center text-sm md:text-sm"
4856
+ }
4857
+ ),
4858
+ /* @__PURE__ */ jsx11(
4859
+ StepperButton,
4860
+ {
4861
+ label: `Increase ${input.key}`,
4862
+ disabled: disabled || current >= max,
4863
+ browserAttributes: gameplayActuatorAttributes({
4864
+ descriptor,
4865
+ draftDigest: interactionDraftDigestForValues(
4866
+ descriptor,
4867
+ handle.values
4868
+ ),
4869
+ inputKey: input.key,
4870
+ intent: "increment",
4871
+ enabled: !(disabled || current >= max),
4872
+ actuatorKind: "click",
4873
+ actuatorId: `bounded-increment:${input.key}`,
4874
+ semanticEffects: gameplayScalarStepMetadata({
4875
+ inputKey: input.key,
4876
+ value: Math.max(min, Math.min(max, current + step))
4877
+ }).semanticEffects
4878
+ }),
4879
+ onClick: () => update(current + step),
4880
+ children: "+"
4881
+ }
4882
+ )
4883
+ ]
4884
+ }
4885
+ )
3987
4886
  }
3988
4887
  );
3989
4888
  }
3990
- function ChoiceListField({
4889
+ function TargetSummaryField({
3991
4890
  input,
3992
4891
  value,
3993
- setValue,
3994
4892
  errors,
3995
4893
  missing,
3996
- disabled,
3997
- domain
4894
+ domain
4895
+ }) {
4896
+ const target = inputTargetKind(domain) ?? "target";
4897
+ return /* @__PURE__ */ jsx11(FieldFrame, { label: labelForInput(input), errors, missing, children: /* @__PURE__ */ jsx11("span", { children: Array.isArray(value) ? value.length > 0 ? `${value.length} selected: ${value.join(", ")}` : `Select ${targetSelectionLabel(domain)}.` : typeof value === "string" ? value : `Select a ${target} on the board.` }) });
4898
+ }
4899
+ function targetSelectionLabel(domain) {
4900
+ const target = inputTargetKind(domain) ?? "target";
4901
+ const selection = isTargetDomain(domain) ? domain.selection : void 0;
4902
+ if (selection?.mode !== "many") return `a ${target}`;
4903
+ const min = selection.min ?? 0;
4904
+ if (selection.max !== void 0 && min === selection.max) {
4905
+ return `${min} ${target}${min === 1 ? "" : "s"}`;
4906
+ }
4907
+ return `${min}${selection.max ? `-${selection.max}` : "+"} ${target}s`;
4908
+ }
4909
+ function StepperButton({
4910
+ label,
4911
+ disabled,
4912
+ browserAttributes,
4913
+ onClick,
4914
+ children
4915
+ }) {
4916
+ return /* @__PURE__ */ jsx11(
4917
+ ThemedButton,
4918
+ {
4919
+ type: "button",
4920
+ variant: "secondary",
4921
+ size: "sm",
4922
+ "aria-label": label,
4923
+ disabled,
4924
+ ...browserAttributes,
4925
+ onClick,
4926
+ className: "h-8 w-8 text-sm",
4927
+ children
4928
+ }
4929
+ );
4930
+ }
4931
+ function labelForInput(input) {
4932
+ if (input.domain.type === "choice") {
4933
+ const exact = input.domain.choices?.find(
4934
+ (choice) => choice.value === input.defaultValue
4935
+ );
4936
+ if (exact?.label && input.key === exact.value) return exact.label;
4937
+ }
4938
+ return humanize(input.key);
4939
+ }
4940
+ function humanize(key) {
4941
+ return key.replace(/Id$/, "").replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[-_]+/g, " ").replace(/\b\w/g, (letter) => letter.toUpperCase());
4942
+ }
4943
+ function isRecord2(value) {
4944
+ return typeof value === "object" && value !== null && !Array.isArray(value);
4945
+ }
4946
+ function numberOrZero(value) {
4947
+ return typeof value === "number" && Number.isFinite(value) ? value : 0;
4948
+ }
4949
+
4950
+ // src/runtime/components/interaction-form/InteractionForm.tsx
4951
+ import {
4952
+ useEffect as useEffect6,
4953
+ useId as useId2,
4954
+ useMemo as useMemo12,
4955
+ useState as useState4
4956
+ } from "react";
4957
+ import * as AccordionPrimitive from "@radix-ui/react-accordion";
4958
+
4959
+ // src/runtime/components/interaction-form/input-slot.tsx
4960
+ import { Fragment as Fragment8, jsx as jsx12 } from "react/jsx-runtime";
4961
+ function createInteractionInputSlot({
4962
+ descriptor,
4963
+ input,
4964
+ handle,
4965
+ errors,
4966
+ missing,
4967
+ disabled
3998
4968
  }) {
3999
- const theme = useTheme();
4000
- const selected = new Set(Array.isArray(value) ? value : []);
4001
- const min = domain.selection?.mode === "many" ? domain.selection.min ?? 0 : domain.min;
4002
- const max = (domain.selection?.mode === "many" ? domain.selection.max : domain.max) ?? domain.choices?.length ?? Number.POSITIVE_INFINITY;
4003
- const toggle = (choice) => {
4004
- const next = new Set(selected);
4005
- if (next.has(choice)) next.delete(choice);
4006
- else if (next.size < max) next.add(choice);
4007
- setValue([...next]);
4969
+ const value = handle.values[input.key];
4970
+ const resolvedInput = resolveInputDomain(
4971
+ input,
4972
+ handle.values
4973
+ );
4974
+ const targetButton = ({
4975
+ value: targetValue,
4976
+ children,
4977
+ kind,
4978
+ ...buttonProps
4979
+ }) => {
4980
+ const domain = resolvedInput.domain;
4981
+ const eligible = isResolvedTargetDomain(domain) && domain.eligibleTargets.includes(targetValue);
4982
+ const selection = isTargetDomain(domain) ? domain.selection : void 0;
4983
+ const currentValue = handle.values[input.key];
4984
+ const selected = selection?.mode === "many" ? Array.isArray(currentValue) && currentValue.map(String).includes(targetValue) : currentValue !== void 0 && String(currentValue) === targetValue;
4985
+ const isDisabled = disabled || !eligible;
4986
+ const dataAttribute = kind === "card" ? { "data-dreamboard-interaction-card-slot": "" } : { "data-dreamboard-interaction-target-slot": "" };
4987
+ const browserAttributes = gameplayActuatorAttributes({
4988
+ descriptor,
4989
+ draftDigest: interactionDraftDigestForValues(
4990
+ descriptor,
4991
+ handle.values
4992
+ ),
4993
+ inputKey: input.key,
4994
+ intent: selection?.mode === "many" ? "toggle" : "select",
4995
+ candidateValue: targetValue,
4996
+ candidateState: selected ? "selected" : "unselected",
4997
+ enabled: !isDisabled,
4998
+ actuatorKind: "click",
4999
+ actuatorId: `${kind}:${input.key}:${targetValue}`,
5000
+ semanticEffects: gameplayCandidateMetadata({
5001
+ descriptor,
5002
+ draftValues: handle.values,
5003
+ inputKey: input.key,
5004
+ candidateValue: targetValue,
5005
+ intent: selection?.mode === "many" ? "toggle" : "select"
5006
+ }).semanticEffects
5007
+ });
5008
+ return /* @__PURE__ */ jsx12(
5009
+ "button",
5010
+ {
5011
+ type: "button",
5012
+ disabled: isDisabled,
5013
+ "aria-disabled": isDisabled,
5014
+ "aria-pressed": selected,
5015
+ "data-input-name": input.key,
5016
+ "data-target-kind": inputTargetKind(domain),
5017
+ "data-target-value": targetValue,
5018
+ "data-eligible": eligible,
5019
+ "data-selected": selected || void 0,
5020
+ "data-disabled": isDisabled || void 0,
5021
+ ...dataAttribute,
5022
+ ...browserAttributes,
5023
+ ...buttonProps,
5024
+ onClick: () => {
5025
+ if (isDisabled) return;
5026
+ const nextValue = selection?.mode === "many" ? toggleManyValue(currentValue, targetValue, selection) : targetValue;
5027
+ handle.setInput(input.key, nextValue);
5028
+ },
5029
+ children: children ?? targetValue
5030
+ }
5031
+ );
4008
5032
  };
4009
- const meta = min || Number.isFinite(max) ? `Pick ${min ?? 0}${Number.isFinite(max) ? `-${max}` : "+"}` : void 0;
4010
- return /* @__PURE__ */ jsx11(
4011
- FieldFrame,
4012
- {
4013
- label: /* @__PURE__ */ jsxs3(
4014
- "span",
5033
+ return {
5034
+ Field: () => /* @__PURE__ */ jsx12(
5035
+ DefaultInteractionField,
5036
+ {
5037
+ descriptor,
5038
+ input: resolvedInput,
5039
+ handle,
5040
+ value,
5041
+ setValue: (next) => handle.setInput(input.key, next),
5042
+ clearValue: () => handle.clearInput(input.key),
5043
+ errors,
5044
+ missing,
5045
+ disabled
5046
+ }
5047
+ ),
5048
+ Default: ({ children }) => {
5049
+ const hasDefault = "defaultValue" in input;
5050
+ const isDisabled = disabled || !hasDefault;
5051
+ const browserAttributes = gameplayActuatorAttributes({
5052
+ descriptor,
5053
+ draftDigest: interactionDraftDigestForValues(
5054
+ descriptor,
5055
+ handle.values
5056
+ ),
5057
+ inputKey: input.key,
5058
+ intent: "select",
5059
+ candidateValue: input.defaultValue,
5060
+ candidateState: "unselected",
5061
+ enabled: !isDisabled,
5062
+ actuatorKind: "click",
5063
+ actuatorId: `default:${input.key}`,
5064
+ semanticEffects: hasDefault ? gameplayCandidateMetadata({
5065
+ descriptor,
5066
+ draftValues: handle.values,
5067
+ inputKey: input.key,
5068
+ candidateValue: input.defaultValue,
5069
+ intent: "select"
5070
+ }).semanticEffects : void 0
5071
+ });
5072
+ return /* @__PURE__ */ jsx12(
5073
+ "button",
4015
5074
  {
4016
- style: {
4017
- display: "flex",
4018
- justifyContent: "space-between",
4019
- gap: theme.space[2]
5075
+ type: "button",
5076
+ disabled: isDisabled,
5077
+ "aria-disabled": isDisabled,
5078
+ "data-dreamboard-interaction-default-slot": "",
5079
+ "data-input-name": input.key,
5080
+ "data-disabled": isDisabled || void 0,
5081
+ ...browserAttributes,
5082
+ onClick: () => {
5083
+ if (isDisabled) return;
5084
+ handle.setInput(input.key, input.defaultValue);
4020
5085
  },
4021
- children: [
4022
- /* @__PURE__ */ jsx11("span", { children: labelForInput(input) }),
4023
- meta ? /* @__PURE__ */ jsx11("span", { style: { color: theme.semantic.text.muted }, children: meta }) : null
4024
- ]
5086
+ children: children ?? "Use default"
4025
5087
  }
4026
- ),
4027
- errors,
4028
- missing,
4029
- children: /* @__PURE__ */ jsx11("span", { style: { display: "flex", flexWrap: "wrap", gap: theme.space[1] }, children: (domain.choices ?? []).map((choice) => {
4030
- const value2 = choice.value;
4031
- const checked = selected.has(value2);
4032
- return /* @__PURE__ */ jsx11(
4033
- ThemedButton,
4034
- {
4035
- type: "button",
4036
- variant: checked ? "primary" : "secondary",
4037
- size: "sm",
4038
- disabled: disabled || choice.disabled || !checked && selected.size >= max,
4039
- "aria-pressed": checked,
4040
- title: choice.disabledReason ?? choice.description,
4041
- onClick: () => toggle(value2),
4042
- className: "h-8 px-3 text-sm",
4043
- children: /* @__PURE__ */ jsx11(ChoiceOptionLabel, { choice })
4044
- },
4045
- value2
4046
- );
4047
- }) })
5088
+ );
5089
+ },
5090
+ Target: (props) => targetButton({ ...props, kind: "target" }),
5091
+ Card: (props) => targetButton({ ...props, kind: "card" }),
5092
+ Cards: ({ children }) => {
5093
+ const domain = resolvedInput.domain;
5094
+ const targets = isResolvedTargetDomain(domain) ? domain.eligibleTargets : [];
5095
+ return /* @__PURE__ */ jsx12(Fragment8, { children: targets.map((id) => children({ id })) });
5096
+ },
5097
+ Options: ({ children }) => {
5098
+ const domain = resolvedInput.domain;
5099
+ const choices = domain.type === "choice" || domain.type === "choiceList" ? domain.choices ?? [] : [];
5100
+ return /* @__PURE__ */ jsx12(Fragment8, { children: choices.map((choice) => children(choice)) });
5101
+ },
5102
+ Value: ({ children }) => /* @__PURE__ */ jsx12(Fragment8, { children: children(value) }),
5103
+ Label: ({ children }) => /* @__PURE__ */ jsx12(Fragment8, { children: children ?? labelForInput(resolvedInput) }),
5104
+ Message: ({ children }) => {
5105
+ const message = children ?? errors[0] ?? (missing ? "Required" : null);
5106
+ return message ? /* @__PURE__ */ jsx12("span", { role: "alert", "data-dreamboard-interaction-message-slot": "", children: message }) : null;
4048
5107
  }
4049
- );
5108
+ };
4050
5109
  }
4051
- function ResourceMapField({
4052
- input,
4053
- value,
4054
- setValue,
4055
- errors,
4056
- missing,
4057
- disabled,
4058
- domain
5110
+
5111
+ // src/runtime/components/interaction-form/InteractionForm.tsx
5112
+ import { Fragment as Fragment9, jsx as jsx13, jsxs as jsxs4 } from "react/jsx-runtime";
5113
+ function InteractionForm({
5114
+ descriptor,
5115
+ handle,
5116
+ fields,
5117
+ hiddenFields,
5118
+ renderFields,
5119
+ inputs,
5120
+ submit: renderSubmit,
5121
+ title,
5122
+ description,
5123
+ submitLabel,
5124
+ cancelLabel = "Cancel",
5125
+ onCancel,
5126
+ onSubmitSuccess,
5127
+ disabled = false,
5128
+ accordion = true,
5129
+ defaultOpen = false,
5130
+ style
4059
5131
  }) {
4060
5132
  const theme = useTheme();
4061
- const current = isRecord(value) ? value : {};
4062
- const update = (resourceId, delta, min, max) => {
4063
- const previous = numberOrZero(current[resourceId]);
4064
- const next = Math.max(min, Math.min(max, previous + delta));
4065
- setValue({ ...current, [resourceId]: next });
5133
+ const fallbackLabel = interactionLabel(descriptor);
5134
+ const formId = useId2();
5135
+ useChromeSuppression(formId, true);
5136
+ const [pending, setPending] = useState4(false);
5137
+ const [validation, setValidation] = useState4(
5138
+ null
5139
+ );
5140
+ const [formError, setFormError] = useState4(null);
5141
+ const [accordionOpen, setAccordionOpen] = useState4(defaultOpen);
5142
+ const hidden = useMemo12(() => new Set(hiddenFields ?? []), [hiddenFields]);
5143
+ const visibleInputs = useMemo12(() => {
5144
+ if (inputs) {
5145
+ const rendered = new Set(Object.keys(inputs));
5146
+ return resolveInteractionInputs(
5147
+ descriptor,
5148
+ handle.values
5149
+ ).filter((input) => rendered.has(input.key));
5150
+ }
5151
+ const allowed = fields ? new Set(fields) : null;
5152
+ return defaultFormInputs(
5153
+ descriptor,
5154
+ handle.values
5155
+ ).filter((input) => {
5156
+ const key = input.key;
5157
+ if (allowed && !allowed.has(key)) return false;
5158
+ return !hidden.has(key);
5159
+ });
5160
+ }, [descriptor, fields, hidden, handle.values, inputs]);
5161
+ const currentValidation = validation;
5162
+ const fieldErrors = currentValidation?.fieldErrors ?? {};
5163
+ const missing = new Set(currentValidation?.missing ?? []);
5164
+ const formErrors = [
5165
+ ...currentValidation?.formErrors ?? [],
5166
+ ...formError ? [formError] : []
5167
+ ];
5168
+ const isDisabled = disabled || pending || !isInteractionAvailable(descriptor);
5169
+ const useAccordion = accordion && visibleInputs.length > 0;
5170
+ const rootBrowserAttributes = gameplayInteractionRootAttributes({
5171
+ descriptor,
5172
+ draftDigest: interactionDraftDigestForValues(
5173
+ descriptor,
5174
+ handle.values
5175
+ ),
5176
+ ready: handle.isReady,
5177
+ available: !isDisabled
5178
+ });
5179
+ const armBrowserAttributes = gameplayActuatorAttributes({
5180
+ descriptor,
5181
+ draftDigest: interactionDraftDigestForValues(
5182
+ descriptor,
5183
+ handle.values
5184
+ ),
5185
+ intent: "arm",
5186
+ enabled: !isDisabled,
5187
+ actuatorKind: "click",
5188
+ actuatorId: "arm",
5189
+ preparationPatterns: gameplayPreparationPatternsForDescriptor(
5190
+ descriptor,
5191
+ handle.values
5192
+ )
5193
+ });
5194
+ const submitMetadata = gameplaySubmitMetadata({ descriptor });
5195
+ const submitBrowserAttributes = gameplayActuatorAttributes({
5196
+ descriptor,
5197
+ draftDigest: interactionDraftDigestForValues(
5198
+ descriptor,
5199
+ handle.values
5200
+ ),
5201
+ intent: submitMetadata.intent,
5202
+ enabled: !isDisabled && handle.isReady,
5203
+ actuatorKind: "click",
5204
+ actuatorId: "submit",
5205
+ semanticEffects: submitMetadata.semanticEffects
5206
+ });
5207
+ useEffect6(() => {
5208
+ setAccordionOpen(defaultOpen);
5209
+ }, [defaultOpen, descriptor.interactionId]);
5210
+ const containerStyle = {
5211
+ ...surfaceStyle(theme, { tone: "card" }),
5212
+ display: "flex",
5213
+ flexDirection: "column",
5214
+ gap: theme.space[2],
5215
+ padding: theme.space[3],
5216
+ minWidth: "min(100%, 280px)",
5217
+ boxSizing: "border-box",
5218
+ fontFamily: theme.typography.fontFamily.body,
5219
+ ...style
5220
+ };
5221
+ const submit = async (event) => {
5222
+ event.preventDefault();
5223
+ if (isDisabled) return;
5224
+ const nextValidation = handle.validateDraft();
5225
+ setValidation(nextValidation);
5226
+ setFormError(null);
5227
+ if (!nextValidation.ok) {
5228
+ setAccordionOpen(true);
5229
+ return;
5230
+ }
5231
+ setPending(true);
5232
+ try {
5233
+ await handle.submitDraft();
5234
+ onSubmitSuccess?.();
5235
+ setAccordionOpen(defaultOpen);
5236
+ } catch (error) {
5237
+ setAccordionOpen(true);
5238
+ setFormError(
5239
+ error instanceof Error ? error.message : "Interaction submission failed"
5240
+ );
5241
+ } finally {
5242
+ setPending(false);
5243
+ }
4066
5244
  };
4067
- return /* @__PURE__ */ jsx11(FieldFrame, { label: labelForInput(input), errors, missing, children: /* @__PURE__ */ jsx11(
4068
- "span",
5245
+ const header = /* @__PURE__ */ jsxs4("div", { style: { display: "flex", flexDirection: "column", gap: 2 }, children: [
5246
+ /* @__PURE__ */ jsx13(
5247
+ "strong",
5248
+ {
5249
+ style: {
5250
+ fontFamily: theme.typography.fontFamily.display,
5251
+ fontSize: theme.typography.fontSize.md,
5252
+ color: theme.semantic.text.primary
5253
+ },
5254
+ children: title ?? fallbackLabel
5255
+ }
5256
+ ),
5257
+ description ? /* @__PURE__ */ jsx13(
5258
+ "span",
5259
+ {
5260
+ style: {
5261
+ fontSize: theme.typography.fontSize.sm,
5262
+ color: theme.semantic.text.muted
5263
+ },
5264
+ children: description
5265
+ }
5266
+ ) : null
5267
+ ] });
5268
+ const fieldsContent = visibleInputs.length > 0 ? /* @__PURE__ */ jsx13(
5269
+ "div",
4069
5270
  {
4070
5271
  style: {
4071
- display: "grid",
4072
- gridTemplateColumns: "repeat(auto-fit, minmax(140px, 1fr))",
4073
- gap: theme.space[2]
5272
+ display: "flex",
5273
+ flexDirection: "column",
5274
+ gap: theme.space[3]
4074
5275
  },
4075
- children: (domain.resources ?? []).map((resource) => {
4076
- const min = resource.min ?? 0;
4077
- const max = resource.max ?? 0;
4078
- const amount = numberOrZero(current[resource.resourceId]);
4079
- return /* @__PURE__ */ jsxs3(
4080
- "span",
5276
+ children: visibleInputs.map((input) => {
5277
+ const key = input.key;
5278
+ const inputRenderer = inputs?.[key];
5279
+ return /* @__PURE__ */ jsx13(
5280
+ InteractionField,
4081
5281
  {
4082
- style: {
4083
- display: "grid",
4084
- gridTemplateColumns: "minmax(0, 1fr) auto auto auto",
4085
- alignItems: "center",
4086
- gap: theme.space[1],
4087
- padding: theme.space[2],
4088
- borderRadius: theme.radius.md,
4089
- background: theme.semantic.surface.inset
4090
- },
4091
- children: [
4092
- /* @__PURE__ */ jsxs3(
4093
- "span",
4094
- {
4095
- style: {
4096
- minWidth: 0,
4097
- display: "inline-flex",
4098
- alignItems: "center",
4099
- gap: theme.space[1]
4100
- },
4101
- children: [
4102
- resource.icon ? /* @__PURE__ */ jsx11("span", { "aria-hidden": true, style: { fontSize: "1.1em" }, children: resource.icon }) : null,
4103
- resource.label ?? humanize(input.key)
4104
- ]
4105
- }
4106
- ),
4107
- /* @__PURE__ */ jsx11(
4108
- StepperButton,
4109
- {
4110
- label: `Decrease ${resource.label ?? resource.resourceId}`,
4111
- disabled: disabled || amount <= min,
4112
- onClick: () => update(resource.resourceId, -1, min, max),
4113
- children: "-"
4114
- }
4115
- ),
4116
- /* @__PURE__ */ jsx11(
4117
- "span",
4118
- {
4119
- style: {
4120
- minWidth: "2ch",
4121
- textAlign: "center",
4122
- fontVariantNumeric: "tabular-nums"
4123
- },
4124
- children: amount
4125
- }
4126
- ),
4127
- /* @__PURE__ */ jsx11(
4128
- StepperButton,
4129
- {
4130
- label: `Increase ${resource.label ?? resource.resourceId}`,
4131
- disabled: disabled || amount >= max,
4132
- onClick: () => update(resource.resourceId, 1, min, max),
4133
- children: "+"
4134
- }
4135
- )
4136
- ]
5282
+ descriptor,
5283
+ inputKey: key,
5284
+ handle,
5285
+ errors: fieldErrors[key] ?? [],
5286
+ missing: missing.has(key),
5287
+ disabled: isDisabled,
5288
+ render: inputRenderer ? ({ input: input2, errors, missing: missing2, disabled: disabled2 }) => inputRenderer(
5289
+ createInteractionInputSlot({
5290
+ descriptor,
5291
+ input: input2,
5292
+ handle,
5293
+ errors,
5294
+ missing: missing2,
5295
+ disabled: disabled2
5296
+ })
5297
+ ) : renderFields?.[key]
4137
5298
  },
4138
- resource.resourceId
5299
+ input.key
4139
5300
  );
4140
5301
  })
4141
5302
  }
4142
- ) });
4143
- }
4144
- function BoundedNumberField({
4145
- input,
4146
- value,
4147
- setValue,
4148
- errors,
4149
- missing,
4150
- disabled,
4151
- domain
4152
- }) {
4153
- const theme = useTheme();
4154
- const min = domain.min ?? 0;
4155
- const max = domain.max ?? Number.POSITIVE_INFINITY;
4156
- const step = domain.step ?? 1;
4157
- const current = typeof value === "number" ? value : min;
4158
- const controlId = useId();
4159
- const update = (next) => setValue(Math.max(min, Math.min(max, next)));
4160
- return /* @__PURE__ */ jsx11(
4161
- FieldFrame,
5303
+ ) : null;
5304
+ if (visibleInputs.length === 0 && !handle.isReady) {
5305
+ throw new Error(
5306
+ `InteractionForm '${descriptor.interactionKey}' has required inputs that cannot be rendered by the default form. Provide renderFields, select on a surface, or use a default-renderable input domain.`
5307
+ );
5308
+ }
5309
+ const formErrorContent = formErrors.length > 0 ? /* @__PURE__ */ jsx13(
5310
+ "div",
4162
5311
  {
4163
- label: labelForInput(input),
4164
- controlId,
4165
- errors,
4166
- missing,
4167
- children: /* @__PURE__ */ jsxs3(
4168
- "span",
4169
- {
4170
- style: {
4171
- display: "inline-flex",
4172
- alignItems: "center",
4173
- gap: theme.space[1]
4174
- },
4175
- children: [
4176
- /* @__PURE__ */ jsx11(
4177
- StepperButton,
5312
+ role: "alert",
5313
+ style: {
5314
+ display: "flex",
5315
+ flexDirection: "column",
5316
+ gap: theme.space[1],
5317
+ color: theme.semantic.intent.danger.solid,
5318
+ fontSize: theme.typography.fontSize.sm
5319
+ },
5320
+ children: formErrors.map((error) => /* @__PURE__ */ jsx13("span", { children: error }, error))
5321
+ }
5322
+ ) : null;
5323
+ const actions = /* @__PURE__ */ jsxs4(
5324
+ "div",
5325
+ {
5326
+ style: {
5327
+ display: "flex",
5328
+ gap: theme.space[2],
5329
+ justifyContent: "flex-end"
5330
+ },
5331
+ children: [
5332
+ onCancel ? /* @__PURE__ */ jsx13(
5333
+ ThemedButton,
5334
+ {
5335
+ type: "button",
5336
+ variant: "secondary",
5337
+ size: "sm",
5338
+ disabled: pending,
5339
+ onClick: onCancel,
5340
+ className: "h-9 px-3 text-sm",
5341
+ children: cancelLabel
5342
+ }
5343
+ ) : null,
5344
+ renderSubmit ? renderSubmit(
5345
+ {
5346
+ Button: ({ children, ...buttonProps }) => /* @__PURE__ */ jsx13(
5347
+ ThemedButton,
4178
5348
  {
4179
- label: `Decrease ${input.key}`,
4180
- disabled: disabled || current <= min,
4181
- onClick: () => update(current - step),
4182
- children: "-"
5349
+ type: "submit",
5350
+ variant: "primary",
5351
+ size: "sm",
5352
+ disabled: isDisabled,
5353
+ className: "h-9 px-3 text-sm",
5354
+ ...submitBrowserAttributes,
5355
+ ...buttonProps,
5356
+ children: pending ? "Submitting..." : children ?? submitLabel ?? fallbackLabel
4183
5357
  }
4184
- ),
4185
- /* @__PURE__ */ jsx11(
4186
- Input,
5358
+ )
5359
+ },
5360
+ descriptor
5361
+ ) : /* @__PURE__ */ jsx13(
5362
+ ThemedButton,
5363
+ {
5364
+ type: "submit",
5365
+ variant: "primary",
5366
+ size: "sm",
5367
+ disabled: isDisabled,
5368
+ className: "h-9 px-3 text-sm",
5369
+ ...submitBrowserAttributes,
5370
+ children: pending ? "Submitting..." : submitLabel ?? fallbackLabel
5371
+ }
5372
+ )
5373
+ ]
5374
+ }
5375
+ );
5376
+ const body = /* @__PURE__ */ jsxs4(Fragment9, { children: [
5377
+ fieldsContent,
5378
+ formErrorContent,
5379
+ actions
5380
+ ] });
5381
+ return /* @__PURE__ */ jsx13(
5382
+ "form",
5383
+ {
5384
+ "data-interaction-form": true,
5385
+ "data-interaction-id": descriptor.interactionId,
5386
+ onSubmit: (event) => void submit(event),
5387
+ style: containerStyle,
5388
+ ...rootBrowserAttributes,
5389
+ children: useAccordion ? /* @__PURE__ */ jsx13(
5390
+ AccordionPrimitive.Root,
5391
+ {
5392
+ type: "single",
5393
+ collapsible: true,
5394
+ value: accordionOpen ? "fields" : void 0,
5395
+ onValueChange: (value) => setAccordionOpen(value === "fields"),
5396
+ children: /* @__PURE__ */ jsxs4(AccordionPrimitive.Item, { value: "fields", children: [
5397
+ /* @__PURE__ */ jsx13(AccordionPrimitive.Header, { style: { margin: 0 }, children: /* @__PURE__ */ jsxs4(
5398
+ AccordionPrimitive.Trigger,
4187
5399
  {
4188
- id: controlId,
4189
- type: "number",
4190
- min,
4191
- max: Number.isFinite(max) ? max : void 0,
4192
- step,
4193
- value: current,
4194
- disabled,
4195
- onChange: (event) => update(Number(event.target.value)),
4196
- className: "h-9 w-[8ch] px-2 text-center text-sm md:text-sm"
5400
+ ...armBrowserAttributes,
5401
+ style: {
5402
+ alignItems: "center",
5403
+ appearance: "none",
5404
+ background: "transparent",
5405
+ border: 0,
5406
+ color: theme.semantic.text.primary,
5407
+ cursor: "pointer",
5408
+ display: "flex",
5409
+ fontFamily: theme.typography.fontFamily.display,
5410
+ fontSize: theme.typography.fontSize.md,
5411
+ fontWeight: theme.typography.fontWeight.bold,
5412
+ justifyContent: "space-between",
5413
+ padding: 0,
5414
+ textAlign: "left",
5415
+ width: "100%"
5416
+ },
5417
+ children: [
5418
+ /* @__PURE__ */ jsx13("span", { children: title ?? fallbackLabel }),
5419
+ /* @__PURE__ */ jsx13("span", { "aria-hidden": true, children: accordionOpen ? "\u2212" : "+" })
5420
+ ]
4197
5421
  }
4198
- ),
4199
- /* @__PURE__ */ jsx11(
4200
- StepperButton,
5422
+ ) }),
5423
+ /* @__PURE__ */ jsx13(AccordionPrimitive.Content, { children: /* @__PURE__ */ jsxs4(
5424
+ "div",
4201
5425
  {
4202
- label: `Increase ${input.key}`,
4203
- disabled: disabled || current >= max,
4204
- onClick: () => update(current + step),
4205
- children: "+"
5426
+ style: {
5427
+ display: "flex",
5428
+ flexDirection: "column",
5429
+ gap: theme.space[2],
5430
+ marginTop: theme.space[2]
5431
+ },
5432
+ children: [
5433
+ description ? /* @__PURE__ */ jsx13(
5434
+ "span",
5435
+ {
5436
+ style: {
5437
+ fontSize: theme.typography.fontSize.sm,
5438
+ color: theme.semantic.text.muted
5439
+ },
5440
+ children: description
5441
+ }
5442
+ ) : null,
5443
+ body
5444
+ ]
4206
5445
  }
4207
- )
4208
- ]
5446
+ ) })
5447
+ ] })
4209
5448
  }
4210
- )
4211
- }
4212
- );
4213
- }
4214
- function TargetSummaryField({
4215
- input,
4216
- value,
4217
- errors,
4218
- missing,
4219
- domain
4220
- }) {
4221
- const target = inputTargetKind(domain) ?? "target";
4222
- return /* @__PURE__ */ jsx11(FieldFrame, { label: labelForInput(input), errors, missing, children: /* @__PURE__ */ jsx11("span", { children: Array.isArray(value) ? value.length > 0 ? `${value.length} selected: ${value.join(", ")}` : `Select ${targetSelectionLabel(domain)}.` : typeof value === "string" ? value : `Select a ${target} on the board.` }) });
4223
- }
4224
- function targetSelectionLabel(domain) {
4225
- const target = inputTargetKind(domain) ?? "target";
4226
- const selection = isTargetDomain(domain) ? domain.selection : void 0;
4227
- if (selection?.mode !== "many") return `a ${target}`;
4228
- const min = selection.min ?? 0;
4229
- if (selection.max !== void 0 && min === selection.max) {
4230
- return `${min} ${target}${min === 1 ? "" : "s"}`;
4231
- }
4232
- return `${min}${selection.max ? `-${selection.max}` : "+"} ${target}s`;
4233
- }
4234
- function StepperButton({
4235
- label,
4236
- disabled,
4237
- onClick,
4238
- children
4239
- }) {
4240
- return /* @__PURE__ */ jsx11(
4241
- ThemedButton,
4242
- {
4243
- type: "button",
4244
- variant: "secondary",
4245
- size: "sm",
4246
- "aria-label": label,
4247
- disabled,
4248
- onClick,
4249
- className: "h-8 w-8 text-sm",
4250
- children
5449
+ ) : /* @__PURE__ */ jsxs4(Fragment9, { children: [
5450
+ header,
5451
+ body
5452
+ ] })
4251
5453
  }
4252
5454
  );
4253
5455
  }
4254
- function labelForInput(input) {
4255
- if (input.domain.type === "choice") {
4256
- const exact = input.domain.choices?.find(
4257
- (choice) => choice.value === input.defaultValue
4258
- );
4259
- if (exact?.label && input.key === exact.value) return exact.label;
4260
- }
4261
- return humanize(input.key);
4262
- }
4263
- function humanize(key) {
4264
- return key.replace(/Id$/, "").replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[-_]+/g, " ").replace(/\b\w/g, (letter) => letter.toUpperCase());
4265
- }
4266
- function isRecord(value) {
4267
- return typeof value === "object" && value !== null && !Array.isArray(value);
4268
- }
4269
- function numberOrZero(value) {
4270
- return typeof value === "number" && Number.isFinite(value) ? value : 0;
4271
- }
4272
5456
 
4273
- // src/runtime-internal/primitives/interaction-form-binding.tsx
4274
- import { jsx as jsx12 } from "react/jsx-runtime";
5457
+ // src/runtime/primitives/interaction/form.tsx
5458
+ import { jsx as jsx14 } from "react/jsx-runtime";
4275
5459
  function castInteractionHandle(handle) {
4276
5460
  return handle;
4277
5461
  }
@@ -4283,7 +5467,7 @@ function BoundInteractionForm({
4283
5467
  handle,
4284
5468
  ...props
4285
5469
  }) {
4286
- return /* @__PURE__ */ jsx12(
5470
+ return /* @__PURE__ */ jsx14(
4287
5471
  InteractionForm,
4288
5472
  {
4289
5473
  descriptor,
@@ -4292,149 +5476,66 @@ function BoundInteractionForm({
4292
5476
  }
4293
5477
  );
4294
5478
  }
4295
-
4296
- // src/runtime-internal/primitives/dialog-lifecycle.ts
4297
- import { useCallback as useCallback5, useMemo as useMemo12, useState as useState5 } from "react";
4298
- function useDialogLifecycle({
4299
- defaultOpen = true,
4300
- onStateChange
4301
- }) {
4302
- const [state, setState] = useState5(
4303
- defaultOpen ? "open" : "minimized"
4304
- );
4305
- const updateState = useCallback5(
4306
- (nextState) => {
4307
- setState(nextState);
4308
- onStateChange?.(nextState);
4309
- },
4310
- [onStateChange]
4311
- );
4312
- const restore = useCallback5(() => updateState("open"), [updateState]);
4313
- const minimize = useCallback5(() => updateState("minimized"), [updateState]);
4314
- const dismiss = useCallback5(() => updateState("dismissed"), [updateState]);
4315
- const setOpen = useCallback5(
4316
- (open) => {
4317
- updateState(open ? "open" : "minimized");
4318
- },
4319
- [updateState]
4320
- );
4321
- return useMemo12(
4322
- () => ({
4323
- state,
4324
- open: state === "open",
4325
- minimized: state === "minimized",
4326
- dismissed: state === "dismissed",
4327
- setOpen,
4328
- restore,
4329
- minimize,
4330
- dismiss
4331
- }),
4332
- [dismiss, minimize, restore, setOpen, state]
4333
- );
4334
- }
4335
-
4336
- // src/runtime-internal/primitives/interaction.tsx
4337
- import { Fragment as Fragment8, jsx as jsx13 } from "react/jsx-runtime";
4338
- var InteractionContext = createContext9(null);
4339
- function humanizeInteraction(value) {
4340
- const parts = value.split(".");
4341
- const leaf = parts[parts.length - 1] ?? value;
4342
- return leaf.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[-_]+/g, " ").replace(/\s+/g, " ").trim().replace(/^./, (first) => first.toUpperCase());
4343
- }
4344
- function useInteractionPrimitiveContext() {
4345
- const value = useContext9(InteractionContext);
4346
- if (!value) {
4347
- throw new Error(
4348
- "Interaction primitives must be rendered inside <Interaction.Root>."
4349
- );
4350
- }
4351
- return value;
4352
- }
4353
- function useResolvedCardTargetValue() {
4354
- const context = useContext9(InteractionContext);
4355
- const descriptor = context?.descriptor;
4356
- const handle = context?.handle;
4357
- if (!descriptor || !handle) return void 0;
4358
- const cardInput = descriptor.inputs.find(
4359
- (input) => isTargetDomain(input.domain) && input.domain.type === "cardTarget"
4360
- );
4361
- if (!cardInput) return void 0;
4362
- return handle.values[cardInput.key];
4363
- }
4364
- function useInteractionDescriptor(interaction) {
4365
- return usePluginState(
4366
- (state) => state.gameplay.availableInteractions.find(
4367
- (descriptor) => descriptor.interactionKey === interaction || descriptor.interactionId === interaction
4368
- )
5479
+ function InteractionFormPrimitive(props) {
5480
+ const { descriptor, handle } = useInteractionPrimitiveContext();
5481
+ if (!descriptor || !handle) return null;
5482
+ return /* @__PURE__ */ jsx14(
5483
+ BoundInteractionForm,
5484
+ {
5485
+ descriptor,
5486
+ handle,
5487
+ ...props
5488
+ }
4369
5489
  );
4370
5490
  }
4371
- function ResolvedInteractionRoot({
4372
- interaction,
4373
- descriptor,
4374
- children
4375
- }) {
4376
- const handle = useInteractionHandle(descriptor);
4377
- const value = useMemo13(
4378
- () => ({ interaction, descriptor, handle }),
4379
- [descriptor, handle, interaction]
5491
+ function InteractionFieldPrimitive({ input, ...props }) {
5492
+ const { descriptor, handle } = useInteractionPrimitiveContext();
5493
+ if (!descriptor || !handle) return null;
5494
+ return /* @__PURE__ */ jsx14(
5495
+ InteractionField,
5496
+ {
5497
+ descriptor,
5498
+ handle: castInteractionHandle(handle),
5499
+ inputKey: input,
5500
+ ...props
5501
+ }
4380
5502
  );
4381
- return /* @__PURE__ */ jsx13(InteractionContext.Provider, { value, children });
4382
5503
  }
4383
- function InteractionRoot({
4384
- interaction,
4385
- children,
4386
- unavailable = "render"
4387
- }) {
4388
- const descriptor = useInteractionDescriptor(interaction);
4389
- if (!descriptor) {
4390
- if (unavailable === "hide") return null;
4391
- return /* @__PURE__ */ jsx13(
4392
- InteractionContext.Provider,
4393
- {
4394
- value: {
4395
- interaction,
4396
- descriptor: null,
4397
- handle: null
4398
- },
4399
- children
4400
- }
4401
- );
4402
- }
4403
- if (!isInteractionAvailable(descriptor) && unavailable === "hide") {
4404
- return null;
5504
+
5505
+ // src/runtime/primitives/interaction/state.tsx
5506
+ import { Fragment as Fragment10, jsx as jsx15 } from "react/jsx-runtime";
5507
+ function InteractionState({ children, unavailable }) {
5508
+ const { interaction, descriptor, handle } = useInteractionPrimitiveContext();
5509
+ const store = useInteractionUiStore();
5510
+ if (!descriptor || !handle) {
5511
+ return /* @__PURE__ */ jsx15(Fragment10, { children: unavailable });
4405
5512
  }
4406
- return /* @__PURE__ */ jsx13(ResolvedInteractionRoot, { interaction, descriptor, children });
4407
- }
4408
- function InteractionDialog({
4409
- defaultOpen = false,
4410
- onStateChange,
4411
- children
4412
- }) {
4413
- const { interaction } = useInteractionPrimitiveContext();
4414
- const pendingInteractionKey = usePendingInteractionKey();
4415
- const pendingInteractionRevision = usePendingInteractionRevision();
4416
- const lifecycle = useDialogLifecycle({ defaultOpen, onStateChange });
4417
- const restoredRevisionRef = useRef4(null);
4418
- useEffect7(() => {
4419
- if (pendingInteractionKey === interaction && restoredRevisionRef.current !== pendingInteractionRevision) {
4420
- restoredRevisionRef.current = pendingInteractionRevision;
4421
- lifecycle.restore();
4422
- }
4423
- }, [
4424
- interaction,
4425
- lifecycle,
4426
- pendingInteractionKey,
4427
- pendingInteractionRevision
4428
- ]);
4429
- const renderState = useMemo13(
4430
- () => ({
4431
- interaction,
4432
- ...lifecycle
4433
- }),
4434
- [interaction, lifecycle]
5513
+ const typedHandle = castInteractionHandle(handle);
5514
+ const liveDraft = castInteractionDraft(
5515
+ store.getDraft(descriptor.interactionKey)
4435
5516
  );
4436
- return /* @__PURE__ */ jsx13(Fragment8, { children: children(renderState) });
5517
+ const inputKeys = descriptor.inputs.map((input) => input.key);
5518
+ const readiness = getInteractionDraftReadiness(descriptor, liveDraft);
5519
+ return /* @__PURE__ */ jsx15(Fragment10, { children: children({
5520
+ interaction,
5521
+ descriptor,
5522
+ handle: typedHandle,
5523
+ draft: liveDraft,
5524
+ values: typedHandle.values,
5525
+ status: typedHandle.status,
5526
+ available: typedHandle.available,
5527
+ isReady: readiness.ready,
5528
+ isArmed: typedHandle.isArmed,
5529
+ inputKeys,
5530
+ missingInputs: readiness.missingInputs,
5531
+ readyFrontier: readiness.readyFrontier,
5532
+ blockedInputs: readiness.blockedInputs,
5533
+ hasInputs: inputKeys.length > 0
5534
+ }) });
4437
5535
  }
5536
+
5537
+ // src/runtime/primitives/interaction/routes.tsx
5538
+ import { Fragment as Fragment11, jsx as jsx16 } from "react/jsx-runtime";
4438
5539
  function InteractionSwitch({
4439
5540
  interaction,
4440
5541
  routes,
@@ -4448,11 +5549,11 @@ function InteractionSwitch({
4448
5549
  const descriptor = routedInteraction ? descriptors.find(
4449
5550
  (candidate) => candidate.interactionKey === routedInteraction
4450
5551
  ) : void 0;
4451
- if (!descriptor) return /* @__PURE__ */ jsx13(Fragment8, { children: fallback });
5552
+ if (!descriptor) return /* @__PURE__ */ jsx16(Fragment11, { children: fallback });
4452
5553
  const route = routes[descriptor.interactionKey] ?? null;
4453
- if (!route) return /* @__PURE__ */ jsx13(Fragment8, { children: fallback });
5554
+ if (!route) return /* @__PURE__ */ jsx16(Fragment11, { children: fallback });
4454
5555
  const typedInteraction = descriptor.interactionKey;
4455
- return /* @__PURE__ */ jsx13(InteractionRoot, { interaction: typedInteraction, children: route({
5556
+ return /* @__PURE__ */ jsx16(InteractionRoot, { interaction: typedInteraction, children: route({
4456
5557
  interaction: typedInteraction,
4457
5558
  descriptor
4458
5559
  }) });
@@ -4471,7 +5572,7 @@ function InteractionRoutes({
4471
5572
  const descriptors = usePluginState(
4472
5573
  (state) => state.gameplay.availableInteractions
4473
5574
  );
4474
- if (descriptors.length === 0) return /* @__PURE__ */ jsx13(Fragment8, { children: fallback });
5575
+ if (descriptors.length === 0) return /* @__PURE__ */ jsx16(Fragment11, { children: fallback });
4475
5576
  const routedDescriptors = descriptors.filter(
4476
5577
  (descriptor) => includeUnavailable || isInteractionAvailable(descriptor)
4477
5578
  ).map((descriptor) => {
@@ -4493,56 +5594,87 @@ function InteractionRoutes({
4493
5594
  }
4494
5595
  return descriptor;
4495
5596
  });
4496
- if (routedDescriptors.length === 0) return /* @__PURE__ */ jsx13(Fragment8, { children: fallback });
5597
+ if (routedDescriptors.length === 0) return /* @__PURE__ */ jsx16(Fragment11, { children: fallback });
4497
5598
  return null;
4498
5599
  }
4499
- function InteractionLabel({ children, ...props }) {
4500
- const { descriptor, interaction } = useInteractionPrimitiveContext();
4501
- return renderPrimitive("span", {
4502
- ...props,
4503
- "data-dreamboard-interaction-label": "",
4504
- children: children ?? (descriptor ? interactionLabel(descriptor) : humanizeInteraction(interaction))
4505
- });
4506
- }
4507
- function InteractionDescription({
4508
- children,
4509
- ...props
4510
- }) {
4511
- const content = children;
4512
- if (!content) return null;
4513
- return renderPrimitive("span", {
4514
- ...props,
4515
- "data-dreamboard-interaction-description": "",
4516
- children: content
4517
- });
4518
- }
4519
- function InteractionUnavailableMessage({
4520
- children,
4521
- ...props
5600
+
5601
+ // src/runtime/primitives/interaction/dialog.tsx
5602
+ import { useEffect as useEffect7, useMemo as useMemo14, useRef as useRef4 } from "react";
5603
+
5604
+ // src/ui/primitives/dialog-lifecycle.ts
5605
+ import { useCallback as useCallback5, useMemo as useMemo13, useState as useState5 } from "react";
5606
+ function useDialogLifecycle({
5607
+ defaultOpen = true,
5608
+ onStateChange
4522
5609
  }) {
4523
- const { descriptor, handle } = useInteractionPrimitiveContext();
4524
- const reason = children ?? handle?.unavailableReason ?? interactionUnavailableReason(descriptor);
4525
- if (!reason) return null;
4526
- return renderPrimitive("span", {
4527
- ...props,
4528
- "data-dreamboard-interaction-unavailable": "",
4529
- children: reason
4530
- });
5610
+ const [state, setState] = useState5(
5611
+ defaultOpen ? "open" : "minimized"
5612
+ );
5613
+ const updateState = useCallback5(
5614
+ (nextState) => {
5615
+ setState(nextState);
5616
+ onStateChange?.(nextState);
5617
+ },
5618
+ [onStateChange]
5619
+ );
5620
+ const restore = useCallback5(() => updateState("open"), [updateState]);
5621
+ const minimize = useCallback5(() => updateState("minimized"), [updateState]);
5622
+ const dismiss = useCallback5(() => updateState("dismissed"), [updateState]);
5623
+ const setOpen = useCallback5(
5624
+ (open) => {
5625
+ updateState(open ? "open" : "minimized");
5626
+ },
5627
+ [updateState]
5628
+ );
5629
+ return useMemo13(
5630
+ () => ({
5631
+ state,
5632
+ open: state === "open",
5633
+ minimized: state === "minimized",
5634
+ dismissed: state === "dismissed",
5635
+ setOpen,
5636
+ restore,
5637
+ minimize,
5638
+ dismiss
5639
+ }),
5640
+ [dismiss, minimize, restore, setOpen, state]
5641
+ );
4531
5642
  }
4532
- function InteractionValidationMessage({
4533
- children,
4534
- ...props
5643
+
5644
+ // src/runtime/primitives/interaction/dialog.tsx
5645
+ import { Fragment as Fragment12, jsx as jsx17 } from "react/jsx-runtime";
5646
+ function InteractionDialog({
5647
+ defaultOpen = false,
5648
+ onStateChange,
5649
+ children
4535
5650
  }) {
4536
- const { handle } = useInteractionPrimitiveContext();
4537
- const validation = handle?.validateDraft();
4538
- const message = children ?? validation?.formErrors[0] ?? Object.values(validation?.fieldErrors ?? {})[0]?.[0] ?? (validation?.missing[0] ? `${String(validation.missing[0])} is required.` : null);
4539
- if (!message) return null;
4540
- return renderPrimitive("span", {
4541
- ...props,
4542
- "data-dreamboard-interaction-validation": "",
4543
- children: message
4544
- });
5651
+ const { interaction } = useInteractionPrimitiveContext();
5652
+ const pendingInteractionKey = usePendingInteractionKey();
5653
+ const pendingInteractionRevision = usePendingInteractionRevision();
5654
+ const lifecycle = useDialogLifecycle({ defaultOpen, onStateChange });
5655
+ const restoredRevisionRef = useRef4(null);
5656
+ useEffect7(() => {
5657
+ if (pendingInteractionKey === interaction && restoredRevisionRef.current !== pendingInteractionRevision) {
5658
+ restoredRevisionRef.current = pendingInteractionRevision;
5659
+ lifecycle.restore();
5660
+ }
5661
+ }, [
5662
+ interaction,
5663
+ lifecycle,
5664
+ pendingInteractionKey,
5665
+ pendingInteractionRevision
5666
+ ]);
5667
+ const renderState = useMemo14(
5668
+ () => ({
5669
+ interaction,
5670
+ ...lifecycle
5671
+ }),
5672
+ [interaction, lifecycle]
5673
+ );
5674
+ return /* @__PURE__ */ jsx17(Fragment12, { children: children(renderState) });
4545
5675
  }
5676
+
5677
+ // src/runtime/primitives/interaction/controls.tsx
4546
5678
  function InteractionTrigger({
4547
5679
  disabled,
4548
5680
  onClick,
@@ -4554,6 +5686,18 @@ function InteractionTrigger({
4554
5686
  return renderPrimitive("button", {
4555
5687
  type: "button",
4556
5688
  ...props,
5689
+ ...descriptor ? gameplayActuatorAttributes({
5690
+ descriptor,
5691
+ draftDigest: descriptor.draftDigest,
5692
+ intent: "arm",
5693
+ enabled: !isDisabled,
5694
+ actuatorKind: "click",
5695
+ actuatorId: "primitive-trigger",
5696
+ preparationPatterns: gameplayPreparationPatternsForDescriptor(
5697
+ descriptor,
5698
+ handle?.values ?? {}
5699
+ )
5700
+ }) : {},
4557
5701
  disabled: isDisabled,
4558
5702
  "aria-disabled": isDisabled,
4559
5703
  "data-dreamboard-interaction-trigger": "",
@@ -4567,60 +5711,6 @@ function InteractionTrigger({
4567
5711
  })
4568
5712
  });
4569
5713
  }
4570
- function InteractionState({ children, unavailable }) {
4571
- const { interaction, descriptor, handle } = useInteractionPrimitiveContext();
4572
- const store = useInteractionUiStore();
4573
- if (!descriptor || !handle) {
4574
- return /* @__PURE__ */ jsx13(Fragment8, { children: unavailable });
4575
- }
4576
- const typedHandle = castInteractionHandle(handle);
4577
- const liveDraft = castInteractionDraft(
4578
- store.getDraft(descriptor.interactionKey)
4579
- );
4580
- const inputKeys = descriptor.inputs.map((input) => input.key);
4581
- const readiness = getInteractionDraftReadiness(descriptor, liveDraft);
4582
- return /* @__PURE__ */ jsx13(Fragment8, { children: children({
4583
- interaction,
4584
- descriptor,
4585
- handle: typedHandle,
4586
- draft: liveDraft,
4587
- values: typedHandle.values,
4588
- status: typedHandle.status,
4589
- available: typedHandle.available,
4590
- isReady: readiness.ready,
4591
- isArmed: typedHandle.isArmed,
4592
- inputKeys,
4593
- missingInputs: readiness.missingInputs,
4594
- readyFrontier: readiness.readyFrontier,
4595
- blockedInputs: readiness.blockedInputs,
4596
- hasInputs: inputKeys.length > 0
4597
- }) });
4598
- }
4599
- function InteractionFormPrimitive(props) {
4600
- const { descriptor, handle } = useInteractionPrimitiveContext();
4601
- if (!descriptor || !handle) return null;
4602
- return /* @__PURE__ */ jsx13(
4603
- BoundInteractionForm,
4604
- {
4605
- descriptor,
4606
- handle,
4607
- ...props
4608
- }
4609
- );
4610
- }
4611
- function InteractionFieldPrimitive({ input, ...props }) {
4612
- const { descriptor, handle } = useInteractionPrimitiveContext();
4613
- if (!descriptor || !handle) return null;
4614
- return /* @__PURE__ */ jsx13(
4615
- InteractionField,
4616
- {
4617
- descriptor,
4618
- handle: castInteractionHandle(handle),
4619
- inputKey: input,
4620
- ...props
4621
- }
4622
- );
4623
- }
4624
5714
  function InteractionSubmit({
4625
5715
  disabled,
4626
5716
  onClick,
@@ -4633,11 +5723,21 @@ function InteractionSubmit({
4633
5723
  const gameActionError = useGameActionError();
4634
5724
  const isSubmitting = handle?.status === "submitting";
4635
5725
  const hasExplicitParams = params !== void 0;
5726
+ const submitMetadata = descriptor ? gameplaySubmitMetadata({ descriptor, explicitParams: hasExplicitParams }) : null;
4636
5727
  const available = isInteractionAvailable(descriptor);
4637
5728
  const isDisabled = disabled === true || !available || !hasExplicitParams && !handle?.isReady || isSubmitting;
4638
5729
  return renderPrimitive("button", {
4639
5730
  type: "button",
4640
5731
  ...props,
5732
+ ...descriptor ? gameplayActuatorAttributes({
5733
+ descriptor,
5734
+ draftDigest: descriptor.draftDigest,
5735
+ intent: submitMetadata?.intent ?? "submit",
5736
+ enabled: !isDisabled,
5737
+ actuatorKind: "click",
5738
+ actuatorId: "primitive-submit",
5739
+ semanticEffects: submitMetadata?.semanticEffects
5740
+ }) : {},
4641
5741
  disabled: isDisabled,
4642
5742
  "aria-disabled": isDisabled,
4643
5743
  "data-dreamboard-interaction-submit": "",
@@ -4677,9 +5777,28 @@ function InteractionInput({
4677
5777
  const { descriptor, handle } = useInteractionPrimitiveContext();
4678
5778
  const value = handle?.draft[name];
4679
5779
  const isDisabled = disabled === true || !isInteractionAvailable(descriptor);
5780
+ const inputDescriptor = descriptor ? inputByKey(descriptor, name) : void 0;
5781
+ const resolvedInputDescriptor = inputDescriptor && handle ? resolveInputDomain(
5782
+ inputDescriptor,
5783
+ handle.values
5784
+ ) : void 0;
5785
+ const scalarFillMetadata = resolvedInputDescriptor?.domain.type === "boundedNumber" ? gameplayScalarFillMetadata({
5786
+ inputKey: name,
5787
+ domain: resolvedInputDescriptor.domain
5788
+ }) : void 0;
4680
5789
  return renderPrimitive("input", {
4681
5790
  ...props,
4682
5791
  name,
5792
+ ...descriptor ? gameplayActuatorAttributes({
5793
+ descriptor,
5794
+ draftDigest: descriptor.draftDigest,
5795
+ inputKey: name,
5796
+ intent: "fill",
5797
+ enabled: !isDisabled,
5798
+ actuatorKind: "fill",
5799
+ actuatorId: `primitive-input:${name}`,
5800
+ acceptedEffectPatterns: scalarFillMetadata?.acceptedEffectPatterns
5801
+ }) : {},
4683
5802
  disabled: isDisabled,
4684
5803
  "aria-disabled": isDisabled,
4685
5804
  "data-dreamboard-interaction-input": "",
@@ -4692,6 +5811,60 @@ function InteractionInput({
4692
5811
  })
4693
5812
  });
4694
5813
  }
5814
+
5815
+ // src/runtime/primitives/interaction/parts.tsx
5816
+ function InteractionLabel({ children, ...props }) {
5817
+ const { descriptor, interaction } = useInteractionPrimitiveContext();
5818
+ return renderPrimitive("span", {
5819
+ ...props,
5820
+ "data-dreamboard-interaction-label": "",
5821
+ children: children ?? (descriptor ? interactionLabel(descriptor) : humanizeInteraction(interaction))
5822
+ });
5823
+ }
5824
+ function InteractionDescription({
5825
+ children,
5826
+ ...props
5827
+ }) {
5828
+ const content = children;
5829
+ if (!content) return null;
5830
+ return renderPrimitive("span", {
5831
+ ...props,
5832
+ "data-dreamboard-interaction-description": "",
5833
+ children: content
5834
+ });
5835
+ }
5836
+ function InteractionUnavailableMessage({
5837
+ children,
5838
+ ...props
5839
+ }) {
5840
+ const { descriptor, handle } = useInteractionPrimitiveContext();
5841
+ const reason = children ?? handle?.unavailableReason ?? interactionUnavailableReason(descriptor);
5842
+ if (!reason) return null;
5843
+ return renderPrimitive("span", {
5844
+ ...props,
5845
+ "data-dreamboard-interaction-unavailable": "",
5846
+ children: reason
5847
+ });
5848
+ }
5849
+ function InteractionValidationMessage({
5850
+ children,
5851
+ ...props
5852
+ }) {
5853
+ const { handle } = useInteractionPrimitiveContext();
5854
+ const validation = handle?.validateDraft();
5855
+ const message = children ?? validation?.formErrors[0] ?? Object.values(validation?.fieldErrors ?? {})[0]?.[0] ?? (validation?.missing[0] ? `${String(validation.missing[0])} is required.` : null);
5856
+ if (!message) return null;
5857
+ return renderPrimitive("span", {
5858
+ ...props,
5859
+ "data-dreamboard-interaction-validation": "",
5860
+ children: message
5861
+ });
5862
+ }
5863
+
5864
+ // src/runtime/primitives/interaction/card-input.tsx
5865
+ import {
5866
+ useCallback as useCallback6
5867
+ } from "react";
4695
5868
  function InteractionCardInput({
4696
5869
  input,
4697
5870
  unsafeCardId,
@@ -4802,6 +5975,24 @@ function InteractionCardInput({
4802
5975
  type: "button",
4803
5976
  ...props,
4804
5977
  children: renderedChildren,
5978
+ ...descriptor ? gameplayActuatorAttributes({
5979
+ descriptor,
5980
+ draftDigest: descriptor.draftDigest,
5981
+ inputKey: input,
5982
+ intent: selection?.mode === "many" ? "toggle" : "select",
5983
+ candidateValue: cardId,
5984
+ candidateState: isSelected ? "selected" : "unselected",
5985
+ enabled: !isDisabled,
5986
+ actuatorKind: "click",
5987
+ actuatorId: `primitive-card:${input}:${cardId ?? "missing"}`,
5988
+ semanticEffects: cardId !== void 0 ? gameplayCandidateMetadata({
5989
+ descriptor,
5990
+ draftValues: liveDraft,
5991
+ inputKey: input,
5992
+ candidateValue: cardId,
5993
+ intent: selection?.mode === "many" ? "toggle" : "select"
5994
+ }).semanticEffects : void 0
5995
+ }) : {},
4805
5996
  disabled: isDisabled,
4806
5997
  "aria-disabled": isDisabled,
4807
5998
  "aria-pressed": isSelected,
@@ -4877,6 +6068,8 @@ function isDevelopmentRuntime() {
4877
6068
  const processLike = globalThis.process;
4878
6069
  return processLike?.env?.NODE_ENV !== "production";
4879
6070
  }
6071
+
6072
+ // src/runtime/primitives/interaction/index.ts
4880
6073
  var Interaction = {
4881
6074
  Root: InteractionRoot,
4882
6075
  State: InteractionState,
@@ -4895,8 +6088,8 @@ var Interaction = {
4895
6088
  Submit: InteractionSubmit
4896
6089
  };
4897
6090
 
4898
- // src/runtime-internal/primitives/phase.tsx
4899
- import { Fragment as Fragment9, jsx as jsx14 } from "react/jsx-runtime";
6091
+ // src/runtime/primitives/phase.tsx
6092
+ import { Fragment as Fragment13, jsx as jsx18 } from "react/jsx-runtime";
4900
6093
  function hasRoute(routes, phase) {
4901
6094
  return Object.prototype.hasOwnProperty.call(routes, phase);
4902
6095
  }
@@ -4909,22 +6102,22 @@ function PhaseSwitch({
4909
6102
  }) {
4910
6103
  const phase = usePluginState((state) => state.gameplay.currentPhase);
4911
6104
  if (phase && hasRoute(routes, phase)) {
4912
- return /* @__PURE__ */ jsx14(Fragment9, { children: routes[phase]() });
6105
+ return /* @__PURE__ */ jsx18(Fragment13, { children: routes[phase]() });
4913
6106
  }
4914
- return /* @__PURE__ */ jsx14(Fragment9, { children: renderFallback(fallback, phase) });
6107
+ return /* @__PURE__ */ jsx18(Fragment13, { children: renderFallback(fallback, phase) });
4915
6108
  }
4916
6109
  var Phase = {
4917
6110
  Switch: PhaseSwitch
4918
6111
  };
4919
6112
 
4920
- // src/runtime-internal/primitives/player-roster.tsx
6113
+ // src/runtime/primitives/player-roster.tsx
4921
6114
  import {
4922
6115
  createContext as createContext10,
4923
- Fragment as Fragment10,
6116
+ Fragment as Fragment14,
4924
6117
  useContext as useContext10,
4925
- useMemo as useMemo14
6118
+ useMemo as useMemo15
4926
6119
  } from "react";
4927
- import { Fragment as Fragment11, jsx as jsx15, jsxs as jsxs4 } from "react/jsx-runtime";
6120
+ import { Fragment as Fragment15, jsx as jsx19, jsxs as jsxs5 } from "react/jsx-runtime";
4928
6121
  var PlayerRosterContext = createContext10(
4929
6122
  null
4930
6123
  );
@@ -4955,7 +6148,7 @@ function PlayerRosterRoot({
4955
6148
  const activePlayers = useActivePlayers();
4956
6149
  const turnOrder = usePlayerTurnOrder();
4957
6150
  const { controllingPlayerId, controllablePlayerIds } = usePluginSession();
4958
- const players = useMemo14(() => {
6151
+ const players = useMemo15(() => {
4959
6152
  const orderedPlayerIds = order === "self-first" && controllingPlayerId ? [
4960
6153
  ...turnOrder.filter((pid) => pid === controllingPlayerId),
4961
6154
  ...turnOrder.filter((pid) => pid !== controllingPlayerId)
@@ -4997,11 +6190,11 @@ function PlayerRosterRoot({
4997
6190
  scoreLabel,
4998
6191
  turnOrder
4999
6192
  ]);
5000
- const value = useMemo14(
6193
+ const value = useMemo15(
5001
6194
  () => ({ players }),
5002
6195
  [players]
5003
6196
  );
5004
- return /* @__PURE__ */ jsx15(PlayerRosterContext.Provider, { value, children });
6197
+ return /* @__PURE__ */ jsx19(PlayerRosterContext.Provider, { value, children });
5005
6198
  }
5006
6199
  function PlayerRosterList({
5007
6200
  children,
@@ -5011,13 +6204,13 @@ function PlayerRosterList({
5011
6204
  return renderPrimitive("div", {
5012
6205
  ...props,
5013
6206
  "data-dreamboard-player-roster-list": "",
5014
- children: players.map((player) => /* @__PURE__ */ jsx15(Fragment10, { children: children ? children(player) : /* @__PURE__ */ jsx15(PlayerRosterName, { player }) }, player.playerId))
6207
+ children: players.map((player) => /* @__PURE__ */ jsx19(Fragment14, { children: children ? children(player) : /* @__PURE__ */ jsx19(PlayerRosterName, { player }) }, player.playerId))
5015
6208
  });
5016
6209
  }
5017
6210
  function PlayerRosterEmpty({ children }) {
5018
6211
  const { players } = usePlayerRosterContext();
5019
6212
  if (players.length > 0) return null;
5020
- return /* @__PURE__ */ jsx15(Fragment11, { children });
6213
+ return /* @__PURE__ */ jsx19(Fragment15, { children });
5021
6214
  }
5022
6215
  function PlayerRosterSwitchButton({
5023
6216
  player,
@@ -5078,7 +6271,7 @@ function PlayerRosterBadges({
5078
6271
  return renderPrimitive("span", {
5079
6272
  ...props,
5080
6273
  "data-dreamboard-player-roster-badges": "",
5081
- children: children ?? player.badges.map((badge) => /* @__PURE__ */ jsxs4(
6274
+ children: children ?? player.badges.map((badge) => /* @__PURE__ */ jsxs5(
5082
6275
  "span",
5083
6276
  {
5084
6277
  "data-dreamboard-player-roster-badge": "",
@@ -5103,15 +6296,15 @@ var PlayerRoster = {
5103
6296
  Badges: PlayerRosterBadges
5104
6297
  };
5105
6298
 
5106
- // src/runtime-internal/primitives/prompt.tsx
6299
+ // src/runtime/primitives/prompt.tsx
5107
6300
  import {
5108
- Fragment as Fragment12,
6301
+ Fragment as Fragment16,
5109
6302
  createContext as createContext11,
5110
6303
  useContext as useContext11,
5111
- useMemo as useMemo15
6304
+ useMemo as useMemo16
5112
6305
  } from "react";
5113
6306
 
5114
- // src/runtime-internal/hooks/useSeatInbox.ts
6307
+ // src/runtime/hooks/useSeatInbox.ts
5115
6308
  function useSeatInbox() {
5116
6309
  const interactions = usePluginState(
5117
6310
  (s) => s.gameplay.availableInteractions ?? []
@@ -5144,22 +6337,22 @@ function bucketForDescriptor(descriptor) {
5144
6337
  return "panel";
5145
6338
  }
5146
6339
 
5147
- // src/runtime-internal/primitives/prompt.tsx
5148
- import { Fragment as Fragment13, jsx as jsx16 } from "react/jsx-runtime";
6340
+ // src/runtime/primitives/prompt.tsx
6341
+ import { Fragment as Fragment17, jsx as jsx20 } from "react/jsx-runtime";
5149
6342
  function PromptRoot(props) {
5150
- return /* @__PURE__ */ jsx16(InteractionRoot, { ...props });
6343
+ return /* @__PURE__ */ jsx20(InteractionRoot, { ...props });
5151
6344
  }
5152
6345
  function PromptTitle(props) {
5153
6346
  const { descriptor } = useInteractionPrimitiveContext();
5154
6347
  const context = descriptor?.kind === "prompt" ? descriptor.context : void 0;
5155
- return /* @__PURE__ */ jsx16(InteractionLabel, { ...props, children: props.children ?? context?.title ?? (descriptor ? interactionLabel(descriptor) : void 0) });
6348
+ return /* @__PURE__ */ jsx20(InteractionLabel, { ...props, children: props.children ?? context?.title ?? (descriptor ? interactionLabel(descriptor) : void 0) });
5156
6349
  }
5157
6350
  function PromptMessage(props) {
5158
6351
  const { descriptor } = useInteractionPrimitiveContext();
5159
6352
  const context = descriptor?.kind === "prompt" ? descriptor.context : void 0;
5160
6353
  const message = props.children ?? (typeof context?.payload?.message === "string" ? context.payload.message : void 0);
5161
6354
  if (!message) return null;
5162
- return /* @__PURE__ */ jsx16(InteractionDescription, { ...props, children: message });
6355
+ return /* @__PURE__ */ jsx20(InteractionDescription, { ...props, children: message });
5163
6356
  }
5164
6357
  function PromptOption({
5165
6358
  value,
@@ -5210,7 +6403,7 @@ function PromptOption({
5210
6403
  function PromptOptions({ children }) {
5211
6404
  const { descriptor } = useInteractionPrimitiveContext();
5212
6405
  const options = descriptor?.kind === "prompt" ? descriptor.context.options ?? [] : [];
5213
- return /* @__PURE__ */ jsx16(Fragment13, { children: options.map((option) => /* @__PURE__ */ jsx16(Fragment12, { children: children(option) }, option.id)) });
6406
+ return /* @__PURE__ */ jsx20(Fragment17, { children: options.map((option) => /* @__PURE__ */ jsx20(Fragment16, { children: children(option) }, option.id)) });
5214
6407
  }
5215
6408
  function PromptDialog({
5216
6409
  prompt,
@@ -5219,14 +6412,14 @@ function PromptDialog({
5219
6412
  children
5220
6413
  }) {
5221
6414
  const lifecycle = useDialogLifecycle({ defaultOpen, onStateChange });
5222
- const renderState = useMemo15(
6415
+ const renderState = useMemo16(
5223
6416
  () => ({
5224
6417
  prompt,
5225
6418
  ...lifecycle
5226
6419
  }),
5227
6420
  [lifecycle, prompt]
5228
6421
  );
5229
- return /* @__PURE__ */ jsx16(Fragment13, { children: children(renderState) });
6422
+ return /* @__PURE__ */ jsx20(Fragment17, { children: children(renderState) });
5230
6423
  }
5231
6424
  var PromptInboxContext = createContext11(null);
5232
6425
  function usePromptInboxContext() {
@@ -5240,16 +6433,16 @@ function usePromptInboxContext() {
5240
6433
  }
5241
6434
  function PromptInboxRoot({ children }) {
5242
6435
  const inbox = useSeatInbox();
5243
- return /* @__PURE__ */ jsx16(PromptInboxContext.Provider, { value: { prompts: inbox.prompts }, children });
6436
+ return /* @__PURE__ */ jsx20(PromptInboxContext.Provider, { value: { prompts: inbox.prompts }, children });
5244
6437
  }
5245
6438
  function PromptInboxEmpty({ children }) {
5246
6439
  const { prompts } = usePromptInboxContext();
5247
6440
  if (prompts.length > 0) return null;
5248
- return /* @__PURE__ */ jsx16(Fragment13, { children });
6441
+ return /* @__PURE__ */ jsx20(Fragment17, { children });
5249
6442
  }
5250
6443
  function PromptInboxItems({ children }) {
5251
6444
  const { prompts } = usePromptInboxContext();
5252
- return /* @__PURE__ */ jsx16(Fragment13, { children: prompts.map((prompt) => children(prompt)) });
6445
+ return /* @__PURE__ */ jsx20(Fragment17, { children: prompts.map((prompt) => children(prompt)) });
5253
6446
  }
5254
6447
  var Prompt = {
5255
6448
  Root: PromptRoot,
@@ -5265,9 +6458,9 @@ var PromptInbox = {
5265
6458
  Items: PromptInboxItems
5266
6459
  };
5267
6460
 
5268
- // src/runtime-internal/primitives/dice.tsx
6461
+ // src/runtime/primitives/dice.tsx
5269
6462
  import { createContext as createContext12, useContext as useContext12 } from "react";
5270
- import { jsx as jsx17 } from "react/jsx-runtime";
6463
+ import { jsx as jsx21 } from "react/jsx-runtime";
5271
6464
  var DiceContext = createContext12(null);
5272
6465
  function normalizeDiceState({
5273
6466
  values,
@@ -5287,7 +6480,7 @@ function normalizeDiceState({
5287
6480
  };
5288
6481
  }
5289
6482
  function DiceRoot({ values, count, children }) {
5290
- return /* @__PURE__ */ jsx17(DiceContext.Provider, { value: normalizeDiceState({ values, count }), children });
6483
+ return /* @__PURE__ */ jsx21(DiceContext.Provider, { value: normalizeDiceState({ values, count }), children });
5291
6484
  }
5292
6485
  function useDicePrimitiveContext() {
5293
6486
  const value = useContext12(DiceContext);
@@ -5309,6 +6502,7 @@ export {
5309
6502
  UI,
5310
6503
  usePluginSession,
5311
6504
  RuntimeProvider,
6505
+ RuntimeSemanticProjectionMarker,
5312
6506
  usePluginState,
5313
6507
  InteractionUiProvider,
5314
6508
  isInteractionAvailable,
@@ -5318,8 +6512,6 @@ export {
5318
6512
  GameRoot,
5319
6513
  GameChrome,
5320
6514
  Game,
5321
- composeEventHandlers,
5322
- renderPrimitive,
5323
6515
  useZonePrimitiveContext,
5324
6516
  useOptionalZonePrimitiveContext,
5325
6517
  useZoneCardContext,
@@ -5357,18 +6549,18 @@ export {
5357
6549
  useInteractionPrimitiveContext,
5358
6550
  useResolvedCardTargetValue,
5359
6551
  InteractionRoot,
5360
- InteractionDialog,
6552
+ InteractionFormPrimitive,
6553
+ InteractionState,
5361
6554
  InteractionSwitch,
5362
6555
  InteractionRoutes,
6556
+ InteractionDialog,
6557
+ InteractionTrigger,
6558
+ InteractionSubmit,
6559
+ InteractionInput,
5363
6560
  InteractionLabel,
5364
6561
  InteractionDescription,
5365
6562
  InteractionUnavailableMessage,
5366
6563
  InteractionValidationMessage,
5367
- InteractionTrigger,
5368
- InteractionState,
5369
- InteractionFormPrimitive,
5370
- InteractionSubmit,
5371
- InteractionInput,
5372
6564
  InteractionCardInput,
5373
6565
  Interaction,
5374
6566
  PhaseSwitch,
@@ -5398,4 +6590,4 @@ export {
5398
6590
  DiceValues,
5399
6591
  Dice
5400
6592
  };
5401
- //# sourceMappingURL=chunk-TDSWKVZ4.js.map
6593
+ //# sourceMappingURL=chunk-ADYH6PVT.js.map