@dreamboard-games/sdk 0.2.1-alpha.1 → 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 (372) 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-BBMVT3KG.d.ts → ThemeProvider-DvMl17Ny.d.ts} +1 -1
  4. package/dist/{chunk-NKCRKGR2.js → chunk-3RQEICD3.js} +2 -2
  5. package/dist/{chunk-ZABVH7AO.js → chunk-ADYH6PVT.js} +1336 -1363
  6. package/dist/chunk-ADYH6PVT.js.map +1 -0
  7. package/dist/{chunk-PEI3FIL2.js → chunk-P7VMTJ5D.js} +2 -2
  8. package/dist/{chunk-PEI3FIL2.js.map → chunk-P7VMTJ5D.js.map} +1 -1
  9. package/dist/{chunk-WG4JQL3S.js → chunk-QZ6X4B5P.js} +1177 -1109
  10. package/dist/chunk-QZ6X4B5P.js.map +1 -0
  11. package/dist/{chunk-MZNVHMJ5.js → chunk-TXXLS3OI.js} +405 -309
  12. package/dist/chunk-TXXLS3OI.js.map +1 -0
  13. package/dist/{chunk-FDNZTDD6.js → chunk-W6SGFWXH.js} +48 -44
  14. package/dist/chunk-W6SGFWXH.js.map +1 -0
  15. package/dist/{chunk-MKXPVOUT.js → chunk-Y2AFYBMB.js} +48 -4
  16. package/dist/chunk-Y2AFYBMB.js.map +1 -0
  17. package/dist/{index-BwqPQtBu.d.ts → codegen.d.ts} +57 -565
  18. package/dist/{infrastructure/workspace-codegen.js → codegen.js} +3 -3
  19. package/dist/{components-BoiVSYqx.d.ts → components-DaIqi9QM.d.ts} +48 -37
  20. package/dist/{hex-board-view-1iAyJRFn.d.ts → hex-board-view-UCUjMALd.d.ts} +2 -2
  21. package/dist/{infrastructure/reducer-bundle-abi.d.ts → index.d-BGqVifr_.d.ts} +289 -10
  22. package/dist/index.js +1 -1
  23. package/dist/package-set.d.ts +2 -2
  24. package/dist/package-set.js +1 -1
  25. package/dist/primitive-props-BNHDkgd7.d.ts +16 -0
  26. package/dist/reducer-contract.d.ts +3 -0
  27. package/dist/{infrastructure/reducer-bundle-abi.js → reducer-contract.js} +4 -4
  28. package/dist/reducer.d.ts +185 -179
  29. package/dist/reducer.js +1363 -1372
  30. package/dist/reducer.js.map +1 -1
  31. package/dist/runtime/primitives.d.ts +9 -9
  32. package/dist/runtime/primitives.js +7 -7
  33. package/dist/runtime/runtime-api.d.ts +2 -0
  34. package/dist/runtime/runtime-api.js +1 -0
  35. package/dist/runtime/workspace-contract.d.ts +62 -17
  36. package/dist/runtime/workspace-contract.js +5 -6
  37. package/dist/{runtime-api-CPLm_XDG.d.ts → runtime-api-tGL3ArsB.d.ts} +103 -4
  38. package/dist/runtime.d.ts +11 -57
  39. package/dist/runtime.js +487 -8
  40. package/dist/runtime.js.map +1 -1
  41. package/dist/testing.d.ts +4 -4
  42. package/dist/testing.js.map +1 -1
  43. package/dist/types.d.ts +1531 -85
  44. package/dist/types.js +1 -3
  45. package/dist/types.js.map +1 -1
  46. package/dist/ui/components.d.ts +7 -8
  47. package/dist/ui/components.js +1 -1
  48. package/dist/ui/defaults.d.ts +1 -1
  49. package/dist/ui/{types/player-state.d.ts → player-state.d.ts} +2 -2
  50. package/dist/{ui-contract-rzKBwOLC.d.ts → ui-contract-SctM4ibF.d.ts} +155 -150
  51. package/dist/ui.d.ts +10 -11
  52. package/dist/ui.js +2 -2
  53. package/package.json +30 -75
  54. package/dist/bundle-CDd5FKeD.d.ts +0 -283
  55. package/dist/cards-Sl3b40Mv.d.ts +0 -13
  56. package/dist/chunk-326PGVAA.js +0 -34
  57. package/dist/chunk-326PGVAA.js.map +0 -1
  58. package/dist/chunk-FDNZTDD6.js.map +0 -1
  59. package/dist/chunk-I46YJSOD.js +0 -1
  60. package/dist/chunk-MKXPVOUT.js.map +0 -1
  61. package/dist/chunk-MZNVHMJ5.js.map +0 -1
  62. package/dist/chunk-T52J5RMF.js +0 -1
  63. package/dist/chunk-WG4JQL3S.js.map +0 -1
  64. package/dist/chunk-XV6D3ET4.js +0 -485
  65. package/dist/chunk-XV6D3ET4.js.map +0 -1
  66. package/dist/chunk-ZABVH7AO.js.map +0 -1
  67. package/dist/generated/runtime/primitives.d.ts +0 -13
  68. package/dist/generated/runtime/primitives.js +0 -181
  69. package/dist/generated/runtime/primitives.js.map +0 -1
  70. package/dist/generated/runtime-api.d.ts +0 -3
  71. package/dist/generated/runtime-api.js +0 -2
  72. package/dist/generated/runtime.d.ts +0 -15
  73. package/dist/generated/runtime.js +0 -19
  74. package/dist/generated/runtime.js.map +0 -1
  75. package/dist/generated/workspace-contract.d.ts +0 -15
  76. package/dist/generated/workspace-contract.js +0 -15
  77. package/dist/generated/workspace-contract.js.map +0 -1
  78. package/dist/infrastructure/reducer-bundle-abi.js.map +0 -1
  79. package/dist/infrastructure/workspace-codegen.d.ts +0 -53
  80. package/dist/infrastructure/workspace-codegen.js.map +0 -1
  81. package/dist/manifest-contract-BNHVGFtU.d.ts +0 -9
  82. package/dist/primitive-props-DpKs-GCr.d.ts +0 -11
  83. package/dist/runtime/types/runtime-api.d.ts +0 -1
  84. package/dist/runtime/types/runtime-api.js +0 -2
  85. package/dist/runtime/types/runtime-api.js.map +0 -1
  86. package/dist/runtime-api-3dshj6kK.d.ts +0 -101
  87. package/dist/slots-1GPGihk8.d.ts +0 -8
  88. package/src/browser-interaction/attributes.ts +0 -211
  89. package/src/browser-interaction/canonical.ts +0 -77
  90. package/src/browser-interaction/constants.ts +0 -77
  91. package/src/browser-interaction/effects.ts +0 -176
  92. package/src/browser-interaction/index.ts +0 -111
  93. package/src/browser-interaction/normalize.ts +0 -997
  94. package/src/browser-interaction/registry.ts +0 -70
  95. package/src/browser-interaction/resolve.ts +0 -596
  96. package/src/browser-interaction/schemas.ts +0 -152
  97. package/src/browser-interaction/types.ts +0 -304
  98. package/src/browser-interaction.ts +0 -1
  99. package/src/generated/reducer-contract/builders.ts +0 -90
  100. package/src/generated/reducer-contract/version.ts +0 -9
  101. package/src/generated/reducer-contract/wire.ts +0 -100
  102. package/src/generated/reducer-contract/zod.ts +0 -103
  103. package/src/generated/runtime/primitives.ts +0 -2
  104. package/src/generated/runtime-api.ts +0 -5
  105. package/src/generated/runtime.ts +0 -35
  106. package/src/generated/workspace-contract.ts +0 -2
  107. package/src/index.ts +0 -7
  108. package/src/infrastructure/reducer-bundle-abi.ts +0 -8
  109. package/src/infrastructure/reducer-contract/bundle.ts +0 -37
  110. package/src/infrastructure/workspace-codegen/hex-geometry.ts +0 -69
  111. package/src/infrastructure/workspace-codegen/index.ts +0 -64
  112. package/src/infrastructure/workspace-codegen/manifest-contract.ts +0 -6632
  113. package/src/infrastructure/workspace-codegen/manifest-validation.ts +0 -795
  114. package/src/infrastructure/workspace-codegen/ownership.ts +0 -131
  115. package/src/infrastructure/workspace-codegen/preset-card-sets.ts +0 -169
  116. package/src/infrastructure/workspace-codegen/seeds.ts +0 -1705
  117. package/src/infrastructure/workspace-codegen.ts +0 -1
  118. package/src/package-set.ts +0 -19
  119. package/src/reducer/authoring/contract.ts +0 -157
  120. package/src/reducer/authoring/effect.ts +0 -224
  121. package/src/reducer/authoring/game.ts +0 -23
  122. package/src/reducer/authoring/interaction.ts +0 -98
  123. package/src/reducer/authoring/phase.ts +0 -300
  124. package/src/reducer/authoring/types.ts +0 -70
  125. package/src/reducer/authoring/validation.ts +0 -382
  126. package/src/reducer/authoring/view-stage.ts +0 -68
  127. package/src/reducer/authoring.ts +0 -29
  128. package/src/reducer/bundle/ingress-bundle.ts +0 -491
  129. package/src/reducer/bundle/trusted/engine-instruction-resolver.ts +0 -254
  130. package/src/reducer/bundle/trusted/flow-instruction-resolver.ts +0 -73
  131. package/src/reducer/bundle/trusted/instruction-runner.ts +0 -414
  132. package/src/reducer/bundle/trusted/interaction-authorization.ts +0 -137
  133. package/src/reducer/bundle/trusted/interaction-collectors.ts +0 -859
  134. package/src/reducer/bundle/trusted/interaction-decision.ts +0 -747
  135. package/src/reducer/bundle/trusted/interaction-resolver.ts +0 -95
  136. package/src/reducer/bundle/trusted/interaction-types.ts +0 -174
  137. package/src/reducer/bundle/trusted/lifecycle-runner.ts +0 -427
  138. package/src/reducer/bundle/trusted/projection-builder.ts +0 -680
  139. package/src/reducer/bundle/trusted/projection-context.ts +0 -39
  140. package/src/reducer/bundle/trusted/rng-sampler.ts +0 -150
  141. package/src/reducer/bundle/trusted/runtime-registry.ts +0 -120
  142. package/src/reducer/bundle/trusted/runtime-scope.ts +0 -336
  143. package/src/reducer/bundle/trusted/simultaneous-player.ts +0 -97
  144. package/src/reducer/bundle/trusted/stage-resolver.ts +0 -87
  145. package/src/reducer/bundle/trusted/static-projection.ts +0 -116
  146. package/src/reducer/bundle/trusted/trusted-runtime-args.ts +0 -97
  147. package/src/reducer/bundle/trusted/trusted-runtime-result.ts +0 -39
  148. package/src/reducer/bundle/trusted/trusted-setup-profiles.ts +0 -43
  149. package/src/reducer/bundle/trusted/trusted-state-codec.ts +0 -48
  150. package/src/reducer/bundle/trusted-bundle.ts +0 -97
  151. package/src/reducer/bundle/types.ts +0 -171
  152. package/src/reducer/bundle.ts +0 -2
  153. package/src/reducer/client-param-schemas.ts +0 -57
  154. package/src/reducer/compose.ts +0 -34
  155. package/src/reducer/core/runtime-input.ts +0 -30
  156. package/src/reducer/core/runtime-instruction.ts +0 -59
  157. package/src/reducer/core/types.ts +0 -62
  158. package/src/reducer/definition-index.ts +0 -277
  159. package/src/reducer/derived.ts +0 -106
  160. package/src/reducer/effects.ts +0 -92
  161. package/src/reducer/engine/runtime-instruction-engine.ts +0 -155
  162. package/src/reducer/ingress/decode-runtime-input.ts +0 -7
  163. package/src/reducer/ingress/decode-session-state.ts +0 -9
  164. package/src/reducer/ingress/encode-session-state.ts +0 -6
  165. package/src/reducer/ingress/input-codec.ts +0 -18
  166. package/src/reducer/ingress/phase-schemas.ts +0 -62
  167. package/src/reducer/ingress/raw-types.ts +0 -107
  168. package/src/reducer/ingress/runtime-codec.ts +0 -14
  169. package/src/reducer/ingress/runtime-payload.ts +0 -13
  170. package/src/reducer/ingress/session-codec.ts +0 -392
  171. package/src/reducer/ingress/types.ts +0 -6
  172. package/src/reducer/inputs/boardInput.ts +0 -217
  173. package/src/reducer/inputs/boardTarget.ts +0 -190
  174. package/src/reducer/inputs/cardInput.ts +0 -86
  175. package/src/reducer/inputs/cardTarget.ts +0 -101
  176. package/src/reducer/inputs/choiceTarget.ts +0 -104
  177. package/src/reducer/inputs/defineInputs.ts +0 -71
  178. package/src/reducer/inputs/formInput.ts +0 -809
  179. package/src/reducer/inputs/many.ts +0 -120
  180. package/src/reducer/inputs/promptInput.ts +0 -87
  181. package/src/reducer/inputs/rngInput.ts +0 -58
  182. package/src/reducer/inputs/targetRule.ts +0 -123
  183. package/src/reducer/inputs.ts +0 -41
  184. package/src/reducer/model/definition.ts +0 -1072
  185. package/src/reducer/model/extract.ts +0 -745
  186. package/src/reducer/model/manifest.ts +0 -570
  187. package/src/reducer/model/queries.ts +0 -641
  188. package/src/reducer/model/runtime.ts +0 -264
  189. package/src/reducer/model/spec.ts +0 -1386
  190. package/src/reducer/model/table.ts +0 -260
  191. package/src/reducer/model.ts +0 -7
  192. package/src/reducer/ops.ts +0 -1034
  193. package/src/reducer/parse-utils.ts +0 -28
  194. package/src/reducer/per-player.ts +0 -422
  195. package/src/reducer/rng.ts +0 -69
  196. package/src/reducer/schema-helpers.ts +0 -185
  197. package/src/reducer/setup-bootstrap-helpers.ts +0 -171
  198. package/src/reducer/setup-bootstrap.ts +0 -481
  199. package/src/reducer/table-ops.ts +0 -2671
  200. package/src/reducer/table-queries.ts +0 -372
  201. package/src/reducer/transaction.ts +0 -120
  202. package/src/reducer.ts +0 -314
  203. package/src/runtime/primitives.ts +0 -1
  204. package/src/runtime/types/runtime-api.ts +0 -1
  205. package/src/runtime/workspace-contract.ts +0 -32
  206. package/src/runtime-internal/components/InteractionForm.tsx +0 -1647
  207. package/src/runtime-internal/components/PluginRuntime.tsx +0 -105
  208. package/src/runtime-internal/components/board/target-layer.ts +0 -72
  209. package/src/runtime-internal/context/ClientParamSchemaContext.tsx +0 -44
  210. package/src/runtime-internal/context/InteractionDraftContext.tsx +0 -279
  211. package/src/runtime-internal/context/PluginSessionContext.tsx +0 -47
  212. package/src/runtime-internal/context/PluginStateContext.tsx +0 -303
  213. package/src/runtime-internal/context/RuntimeContext.tsx +0 -96
  214. package/src/runtime-internal/defaults/components.tsx +0 -409
  215. package/src/runtime-internal/defaults/index.ts +0 -11
  216. package/src/runtime-internal/errors/ValidationError.ts +0 -29
  217. package/src/runtime-internal/hooks/useActivePlayers.ts +0 -33
  218. package/src/runtime-internal/hooks/useBoardInteractions.ts +0 -727
  219. package/src/runtime-internal/hooks/useGameSelector.ts +0 -105
  220. package/src/runtime-internal/hooks/useGameView.ts +0 -9
  221. package/src/runtime-internal/hooks/useInteractionByKey.ts +0 -354
  222. package/src/runtime-internal/hooks/useInteractionHandle.ts +0 -438
  223. package/src/runtime-internal/hooks/useIsMyTurn.ts +0 -20
  224. package/src/runtime-internal/hooks/useLobby.ts +0 -76
  225. package/src/runtime-internal/hooks/useMe.ts +0 -48
  226. package/src/runtime-internal/hooks/usePlayerInfo.ts +0 -28
  227. package/src/runtime-internal/hooks/usePlayerTurnOrder.ts +0 -23
  228. package/src/runtime-internal/hooks/usePluginRuntime.ts +0 -147
  229. package/src/runtime-internal/hooks/useSeatInbox.ts +0 -61
  230. package/src/runtime-internal/hooks/useSimultaneousPhase.ts +0 -10
  231. package/src/runtime-internal/index.ts +0 -42
  232. package/src/runtime-internal/internal.ts +0 -43
  233. package/src/runtime-internal/plugin-styles.css +0 -250
  234. package/src/runtime-internal/primitives/board.tsx +0 -530
  235. package/src/runtime-internal/primitives/dialog-lifecycle.ts +0 -58
  236. package/src/runtime-internal/primitives/dice.tsx +0 -79
  237. package/src/runtime-internal/primitives/game-ui-provider.tsx +0 -35
  238. package/src/runtime-internal/primitives/game.tsx +0 -387
  239. package/src/runtime-internal/primitives/hand-intent-adapter.ts +0 -147
  240. package/src/runtime-internal/primitives/hand-surface.tsx +0 -594
  241. package/src/runtime-internal/primitives/index.ts +0 -196
  242. package/src/runtime-internal/primitives/interaction-form-binding.tsx +0 -56
  243. package/src/runtime-internal/primitives/interaction-submit.ts +0 -90
  244. package/src/runtime-internal/primitives/interaction.tsx +0 -1146
  245. package/src/runtime-internal/primitives/phase.tsx +0 -43
  246. package/src/runtime-internal/primitives/player-roster.tsx +0 -302
  247. package/src/runtime-internal/primitives/primitive-props.tsx +0 -101
  248. package/src/runtime-internal/primitives/prompt.tsx +0 -255
  249. package/src/runtime-internal/primitives/ui.tsx +0 -60
  250. package/src/runtime-internal/primitives/zone.tsx +0 -791
  251. package/src/runtime-internal/reducer.ts +0 -30
  252. package/src/runtime-internal/runtime/createPluginRuntimeAPI.ts +0 -605
  253. package/src/runtime-internal/types/plugin-state.ts +0 -514
  254. package/src/runtime-internal/types/reducer-state.ts +0 -24
  255. package/src/runtime-internal/types/runtime-api.ts +0 -114
  256. package/src/runtime-internal/ui-contract.ts +0 -519
  257. package/src/runtime-internal/utils/browser-interaction-effects.ts +0 -240
  258. package/src/runtime-internal/utils/card-intent-adapter.ts +0 -546
  259. package/src/runtime-internal/utils/interaction-draft-digest.ts +0 -252
  260. package/src/runtime-internal/utils/interaction-inputs.ts +0 -492
  261. package/src/runtime-internal/utils/interaction-labels.ts +0 -23
  262. package/src/runtime-internal/utils/interaction-router.ts +0 -273
  263. package/src/runtime-internal/utils/interaction-status.ts +0 -74
  264. package/src/runtime-internal/utils/semantic-projection-digest.ts +0 -407
  265. package/src/runtime-internal/workspace-contract.ts +0 -1170
  266. package/src/runtime.ts +0 -34
  267. package/src/testing/create-expect-api.ts +0 -352
  268. package/src/testing/create-test-runtime.ts +0 -381
  269. package/src/testing/definitions.ts +0 -127
  270. package/src/testing/index.ts +0 -3
  271. package/src/testing.ts +0 -1
  272. package/src/type-stubs/manifest-contract.d.ts +0 -42
  273. package/src/type-stubs/manifest-contract.js +0 -72
  274. package/src/type-stubs/ui-contract.d.ts +0 -5
  275. package/src/type-stubs/ui-contract.js +0 -1
  276. package/src/types/authoring-card-properties.type-test.ts +0 -266
  277. package/src/types/authoring.ts +0 -1282
  278. package/src/types/cards.ts +0 -19
  279. package/src/types/contracts.ts +0 -1550
  280. package/src/types/generated-helpers.ts +0 -35
  281. package/src/types/index.ts +0 -147
  282. package/src/types/slots.ts +0 -11
  283. package/src/types.ts +0 -1
  284. package/src/ui/components/ActionButton.tsx +0 -97
  285. package/src/ui/components/ActionPanel.tsx +0 -315
  286. package/src/ui/components/Card.tsx +0 -378
  287. package/src/ui/components/CardDragSurface.tsx +0 -1076
  288. package/src/ui/components/ChromeSuppressionContext.tsx +0 -70
  289. package/src/ui/components/CostDisplay.tsx +0 -145
  290. package/src/ui/components/DiceRoller.tsx +0 -581
  291. package/src/ui/components/Drawer.tsx +0 -180
  292. package/src/ui/components/ErrorBoundary.tsx +0 -275
  293. package/src/ui/components/GameEndDisplay.tsx +0 -398
  294. package/src/ui/components/GameSkeleton.tsx +0 -260
  295. package/src/ui/components/Hand.tsx +0 -468
  296. package/src/ui/components/HandDock.tsx +0 -299
  297. package/src/ui/components/HandView.tsx +0 -441
  298. package/src/ui/components/MobileHandTray.tsx +0 -381
  299. package/src/ui/components/MoreActions.tsx +0 -143
  300. package/src/ui/components/PhaseIndicator.tsx +0 -341
  301. package/src/ui/components/PlayArea.tsx +0 -146
  302. package/src/ui/components/PrimaryActionButton.tsx +0 -336
  303. package/src/ui/components/PrimaryButton.tsx +0 -45
  304. package/src/ui/components/ResourceCounter.tsx +0 -270
  305. package/src/ui/components/StagingZone.tsx +0 -134
  306. package/src/ui/components/ThemedButton.tsx +0 -113
  307. package/src/ui/components/Toast.tsx +0 -264
  308. package/src/ui/components/board/HexGrid.tsx +0 -1297
  309. package/src/ui/components/board/NetworkGraph.tsx +0 -476
  310. package/src/ui/components/board/SlotSystem.tsx +0 -388
  311. package/src/ui/components/board/SquareGrid.tsx +0 -1165
  312. package/src/ui/components/board/TrackBoard.tsx +0 -496
  313. package/src/ui/components/board/ZoneMap.tsx +0 -448
  314. package/src/ui/components/board/hex-board-view.ts +0 -123
  315. package/src/ui/components/board/index.ts +0 -142
  316. package/src/ui/components/board/interaction-accessibility.ts +0 -21
  317. package/src/ui/components/board/target-layer.ts +0 -67
  318. package/src/ui/components/card-render-content.type-test.ts +0 -27
  319. package/src/ui/components/hand-layout-math.ts +0 -163
  320. package/src/ui/components/hand-pointer-engine.ts +0 -413
  321. package/src/ui/components/index.ts +0 -245
  322. package/src/ui/components.ts +0 -1
  323. package/src/ui/defaults/components.tsx +0 -106
  324. package/src/ui/defaults/index.ts +0 -8
  325. package/src/ui/defaults.ts +0 -1
  326. package/src/ui/errors/ValidationError.ts +0 -29
  327. package/src/ui/helpers/cards.ts +0 -19
  328. package/src/ui/helpers/track-board.ts +0 -211
  329. package/src/ui/hooks/useBoardTopology.ts +0 -316
  330. package/src/ui/hooks/useCards.ts +0 -10
  331. package/src/ui/hooks/useHandCardPointer.ts +0 -381
  332. package/src/ui/hooks/useHandLayout.ts +0 -378
  333. package/src/ui/hooks/useHandPresentation.ts +0 -121
  334. package/src/ui/hooks/useHexBoard.ts +0 -74
  335. package/src/ui/hooks/useHexGrid.ts +0 -185
  336. package/src/ui/hooks/useIsMobile.ts +0 -35
  337. package/src/ui/hooks/usePanZoom.ts +0 -278
  338. package/src/ui/hooks/useSquareBoard.ts +0 -124
  339. package/src/ui/hooks/useSquareGrid.ts +0 -328
  340. package/src/ui/index.ts +0 -98
  341. package/src/ui/internal/ui/alert.tsx +0 -51
  342. package/src/ui/internal/ui/button.tsx +0 -58
  343. package/src/ui/internal/ui/dialog.tsx +0 -134
  344. package/src/ui/internal/ui/input.tsx +0 -21
  345. package/src/ui/internal/ui/label.tsx +0 -21
  346. package/src/ui/internal/ui/select.tsx +0 -129
  347. package/src/ui/internal/ui/tooltip.tsx +0 -54
  348. package/src/ui/internal/ui/utils.ts +0 -5
  349. package/src/ui/plugin-styles.css +0 -250
  350. package/src/ui/primitives/dialog-lifecycle.ts +0 -58
  351. package/src/ui/primitives/dice.tsx +0 -79
  352. package/src/ui/primitives/primitive-props.tsx +0 -101
  353. package/src/ui/theme/ThemeProvider.tsx +0 -252
  354. package/src/ui/theme/board.ts +0 -61
  355. package/src/ui/theme/css-vars.ts +0 -105
  356. package/src/ui/theme/derive.ts +0 -240
  357. package/src/ui/theme/index.ts +0 -61
  358. package/src/ui/theme/presets/arcade.ts +0 -261
  359. package/src/ui/theme/presets/studio.ts +0 -261
  360. package/src/ui/theme/presets/tabletop.ts +0 -266
  361. package/src/ui/theme/tokens.ts +0 -392
  362. package/src/ui/types/hex-color.ts +0 -20
  363. package/src/ui/types/player-state.ts +0 -463
  364. package/src/ui/types/tiled-board.ts +0 -785
  365. package/src/ui/types/visual-state.ts +0 -137
  366. package/src/ui.ts +0 -1
  367. /package/dist/{chunk-NKCRKGR2.js.map → chunk-3RQEICD3.js.map} +0 -0
  368. /package/dist/{chunk-I46YJSOD.js.map → codegen.js.map} +0 -0
  369. /package/dist/{chunk-T52J5RMF.js.map → reducer-contract.js.map} +0 -0
  370. /package/dist/{generated → runtime}/runtime-api.js.map +0 -0
  371. /package/dist/ui/{types/player-state.js → player-state.js} +0 -0
  372. /package/dist/ui/{types/player-state.js.map → player-state.js.map} +0 -0
@@ -1,1076 +0,0 @@
1
- /**
2
- * Controlled drag-to-target surface for the SDK hand and drop-target views.
3
- *
4
- * `CardDragSurface` is the single owner of:
5
- *
6
- * - the drag-lifecycle phase (`idle`/`inspecting`/`dragging`/`settling`/
7
- * `returning`)
8
- * - the registry of drop targets, including their eligibility
9
- * - all committed `CardIntent` emission (`activate`, `previewStart`,
10
- * `previewEnd`, and `drop`)
11
- * - the lifted-card overlay, settle/snap-back animation and live
12
- * announcement
13
- *
14
- * `CardDropTargetView` is a generic controlled drop-target wrapper. It
15
- * registers the underlying DOM element (and its eligible/disabled state) so
16
- * the lifted pointer can be matched without exposing geometry to the
17
- * caller. Its registration is stable: only the `targetId` triggers register/
18
- * unregister; eligibility and label changes flow through `updateTarget`.
19
- *
20
- * `HandView` (and the hook it uses) drives this surface through the
21
- * controller exposed by `useCardDragSurface()`. Pointer events come from
22
- * `HandPointerEngine`'s lift callbacks. Keyboard pickup, target traversal
23
- * and Escape are handled here so that the drag-lifecycle has exactly one
24
- * authoritative owner.
25
- */
26
-
27
- import {
28
- createContext,
29
- useCallback,
30
- useContext,
31
- useEffect,
32
- useId,
33
- useMemo,
34
- useRef,
35
- useState,
36
- type CSSProperties,
37
- type KeyboardEvent,
38
- type ReactNode,
39
- } from "react";
40
- import { createPortal } from "react-dom";
41
- import { clsx } from "clsx";
42
- import { AnimatePresence, motion, type Transition } from "framer-motion";
43
- import { useTheme } from "../theme/ThemeProvider.js";
44
- import {
45
- dropTargetVisualStateDataAttributes,
46
- type CardDropTargetVisualState,
47
- type CardIntent,
48
- } from "../types/visual-state.js";
49
-
50
- interface RegisteredDropTarget {
51
- targetId: string;
52
- disabled: boolean;
53
- eligible: boolean;
54
- element: HTMLElement;
55
- /** Plain-text label used for the live a11y announcement. */
56
- label: string | null;
57
- /** Order hint for keyboard target traversal (lower numbers focus first). */
58
- order: number;
59
- }
60
-
61
- export type DragPhase =
62
- | "idle"
63
- | "inspecting"
64
- | "dragging"
65
- | "settling"
66
- | "returning";
67
-
68
- interface ActiveDragState {
69
- cardId: string;
70
- cardLabel: string | null;
71
- source: "pointer" | "keyboard";
72
- pointerId: number | null;
73
- pointerX: number;
74
- pointerY: number;
75
- grabOffsetX: number;
76
- grabOffsetY: number;
77
- /**
78
- * Source rectangle captured at lift time, used as the snap-back/origin
79
- * geometry for animated returns.
80
- */
81
- sourceRect: { left: number; top: number; width: number; height: number };
82
- content: ReactNode;
83
- overTargetId: string | null;
84
- keyboardFocusedTargetId: string | null;
85
- /** DOM node we should focus when the lifecycle ends. */
86
- sourceFocus: HTMLElement | null;
87
- }
88
-
89
- interface SettlingState {
90
- cardId: string;
91
- source: "pointer" | "keyboard";
92
- pointerX: number;
93
- pointerY: number;
94
- grabOffsetX: number;
95
- grabOffsetY: number;
96
- sourceRect: { left: number; top: number; width: number; height: number };
97
- targetRect: { left: number; top: number; width: number; height: number };
98
- content: ReactNode;
99
- }
100
-
101
- interface ReturningState {
102
- cardId: string;
103
- source: "pointer" | "keyboard";
104
- pointerX: number;
105
- pointerY: number;
106
- grabOffsetX: number;
107
- grabOffsetY: number;
108
- sourceRect: { left: number; top: number; width: number; height: number };
109
- content: ReactNode;
110
- }
111
-
112
- export interface CardDragSurfaceController {
113
- /** Identity of the card currently in the drag-lifecycle, if any. */
114
- activeCardId: string | null;
115
- /** Source of the active drag, if any. */
116
- activeSource: "pointer" | "keyboard" | null;
117
- /** Drag-lifecycle phase. */
118
- phase: DragPhase;
119
- /** Currently highlighted drop target id, if any. */
120
- overTargetId: string | null;
121
- /** Currently keyboard-focused target id, if any. */
122
- keyboardFocusedTargetId: string | null;
123
- /**
124
- * Begin a pointer drag session. Returns `true` if the session started.
125
- */
126
- startPointerDrag: (input: PointerDragInput) => boolean;
127
- /** Update the pointer coordinates of an active pointer drag. */
128
- updatePointer: (point: { x: number; y: number }) => void;
129
- /**
130
- * Commit the active pointer drag at the supplied release position. Emits
131
- * a `drop` intent if the pointer is over an eligible target, or schedules
132
- * a snap back otherwise.
133
- */
134
- releasePointer: (point: { x: number; y: number }) => void;
135
- /** Cancel the active drag (pointer or keyboard) without committing. */
136
- cancelDrag: () => void;
137
- /**
138
- * Begin a keyboard drag session. The first eligible registered target is
139
- * focused automatically.
140
- */
141
- startKeyboardDrag: (input: KeyboardDragInput) => boolean;
142
- /** Move keyboard focus across registered eligible targets. */
143
- moveKeyboardFocus: (direction: "next" | "prev") => void;
144
- /** Commit the active keyboard drag on the focused target. */
145
- commitKeyboardDrop: () => void;
146
- /**
147
- * Record a tap that did not produce a lift. The surface holds the
148
- * `inspecting` phase until another lift, drop, or external dismissal.
149
- */
150
- recordTap: (input: TapInput) => void;
151
- /**
152
- * Record a `previewStart` intent. Surface owns canonical intent emission
153
- * so consumers subscribe in one place.
154
- */
155
- recordPreviewStart: (cardId: string) => void;
156
- /** Record a `previewEnd` intent. */
157
- recordPreviewEnd: (cardId: string) => void;
158
- /**
159
- * Record a desktop/keyboard `activate` intent under the `direct-activate`
160
- * policy. Drag-to-target policy never calls this; it is centralized here
161
- * so that the surface remains the only ingress for `CardIntent`.
162
- */
163
- recordActivate: (cardId: string, source: "tap" | "keyboard") => void;
164
- /** Clear the `inspecting` phase. */
165
- clearInspect: () => void;
166
- /** Total number of currently registered eligible targets. */
167
- eligibleTargetCount: number;
168
- }
169
-
170
- interface TapInput {
171
- cardId: string;
172
- cardEligible: boolean;
173
- cardDisabled: boolean;
174
- sourceFocus?: HTMLElement | null;
175
- }
176
-
177
- interface PointerDragInput {
178
- cardId: string;
179
- cardLabel?: string | null;
180
- pointerId: number;
181
- startX: number;
182
- startY: number;
183
- pointerX: number;
184
- pointerY: number;
185
- grabOffsetX: number;
186
- grabOffsetY: number;
187
- sourceRect: { left: number; top: number; width: number; height: number };
188
- content: ReactNode;
189
- sourceFocus?: HTMLElement | null;
190
- }
191
-
192
- interface KeyboardDragInput {
193
- cardId: string;
194
- cardLabel?: string | null;
195
- cardEligible: boolean;
196
- sourceRect: { left: number; top: number; width: number; height: number };
197
- content: ReactNode;
198
- sourceFocus?: HTMLElement | null;
199
- }
200
-
201
- export interface CardDragSurfaceContextValue {
202
- registerTarget: (target: RegisteredDropTarget) => () => void;
203
- updateTarget: (
204
- targetId: string,
205
- patch: Partial<Omit<RegisteredDropTarget, "targetId" | "element">>,
206
- ) => void;
207
- controller: CardDragSurfaceController;
208
- /** Expose the most recent active card id for visual-state computation. */
209
- activeCardId: string | null;
210
- /** Expose the highlighted target id for visual-state computation. */
211
- overTargetId: string | null;
212
- /** Expose whether any drag is in progress. */
213
- dragActive: boolean;
214
- keyboardFocusedTargetId: string | null;
215
- }
216
-
217
- const CardDragSurfaceContext =
218
- createContext<CardDragSurfaceContextValue | null>(null);
219
-
220
- export function useCardDragSurface(): CardDragSurfaceContextValue | null {
221
- return useContext(CardDragSurfaceContext);
222
- }
223
-
224
- export interface CardDragSurfaceProps {
225
- onCardIntent?: (intent: CardIntent) => void;
226
- /**
227
- * Approximate inset (px) used for the deterministic hit test. Defaults to
228
- * `8`. Lowering this lets edges register more aggressively; raising it
229
- * makes overlapping targets less ambiguous.
230
- */
231
- hitTestInsetPx?: number;
232
- /** Suppress the live a11y announcement (for environments providing their own). */
233
- suppressLiveAnnouncement?: boolean;
234
- /** Animation transition tunable for settle/return. */
235
- motionTransition?: Transition;
236
- className?: string;
237
- style?: CSSProperties;
238
- children: ReactNode;
239
- }
240
-
241
- const SETTLE_TRANSITION: Transition = {
242
- type: "spring",
243
- stiffness: 380,
244
- damping: 32,
245
- mass: 0.9,
246
- };
247
- const RETURN_TRANSITION: Transition = {
248
- type: "spring",
249
- stiffness: 320,
250
- damping: 26,
251
- mass: 0.8,
252
- };
253
- const REDUCED_TRANSITION: Transition = { duration: 0 };
254
-
255
- export function CardDragSurface({
256
- onCardIntent,
257
- hitTestInsetPx = 8,
258
- suppressLiveAnnouncement = false,
259
- motionTransition,
260
- className,
261
- style,
262
- children,
263
- }: CardDragSurfaceProps) {
264
- const theme = useTheme();
265
- const reducedMotion = theme.motion.reducedMotion === "true";
266
- const liveRegionId = useId();
267
- const targetsRef = useRef(new Map<string, RegisteredDropTarget>());
268
- const orderCounterRef = useRef(0);
269
- const activeDragRef = useRef<ActiveDragState | null>(null);
270
- const inspectingRef = useRef<string | null>(null);
271
- const [activeDrag, setActiveDrag] = useState<ActiveDragState | null>(null);
272
- const [inspectingCardId, setInspectingCardId] = useState<string | null>(null);
273
- const [settlingState, setSettlingState] = useState<SettlingState | null>(
274
- null,
275
- );
276
- const [returningState, setReturningState] = useState<ReturningState | null>(
277
- null,
278
- );
279
- const onIntentRef = useRef(onCardIntent);
280
- onIntentRef.current = onCardIntent;
281
-
282
- const settleTransition = motionTransition ?? SETTLE_TRANSITION;
283
- const returnTransition = motionTransition ?? RETURN_TRANSITION;
284
-
285
- const setActive = useCallback((next: ActiveDragState | null) => {
286
- activeDragRef.current = next;
287
- setActiveDrag(next);
288
- }, []);
289
-
290
- const setInspecting = useCallback((next: string | null) => {
291
- inspectingRef.current = next;
292
- setInspectingCardId(next);
293
- }, []);
294
-
295
- const finalizeInteraction = useCallback((sourceFocus: HTMLElement | null) => {
296
- if (sourceFocus) {
297
- // Defer focus restoration so animation can complete first frame.
298
- queueMicrotask(() => {
299
- try {
300
- sourceFocus.focus({ preventScroll: true });
301
- } catch {
302
- // Source may have been unmounted; ignore.
303
- }
304
- });
305
- }
306
- }, []);
307
-
308
- const registerTarget = useCallback(
309
- (target: RegisteredDropTarget) => {
310
- targetsRef.current.set(target.targetId, {
311
- ...target,
312
- order: target.order || ++orderCounterRef.current,
313
- });
314
- return () => {
315
- targetsRef.current.delete(target.targetId);
316
- const active = activeDragRef.current;
317
- if (active && active.keyboardFocusedTargetId === target.targetId) {
318
- setActive({ ...active, keyboardFocusedTargetId: null });
319
- }
320
- };
321
- },
322
- [setActive],
323
- );
324
-
325
- const updateTarget = useCallback(
326
- (
327
- targetId: string,
328
- patch: Partial<Omit<RegisteredDropTarget, "targetId" | "element">>,
329
- ) => {
330
- const existing = targetsRef.current.get(targetId);
331
- if (!existing) return;
332
- targetsRef.current.set(targetId, { ...existing, ...patch });
333
- },
334
- [],
335
- );
336
-
337
- const isTargetUsable = useCallback((target: RegisteredDropTarget) => {
338
- return !target.disabled && target.eligible !== false;
339
- }, []);
340
-
341
- const resolveDropTarget = useCallback(
342
- (point: { x: number; y: number }): string | null => {
343
- for (const target of targetsRef.current.values()) {
344
- if (!isTargetUsable(target)) continue;
345
- const rect = target.element.getBoundingClientRect();
346
- if (
347
- point.x >= rect.left + hitTestInsetPx &&
348
- point.x <= rect.right - hitTestInsetPx &&
349
- point.y >= rect.top + hitTestInsetPx &&
350
- point.y <= rect.bottom - hitTestInsetPx
351
- ) {
352
- return target.targetId;
353
- }
354
- }
355
- return null;
356
- },
357
- [hitTestInsetPx, isTargetUsable],
358
- );
359
-
360
- const sortedUsableTargetIds = useCallback((): string[] => {
361
- const entries = Array.from(targetsRef.current.values()).filter((t) =>
362
- isTargetUsable(t),
363
- );
364
- entries.sort((a, b) => a.order - b.order);
365
- return entries.map((t) => t.targetId);
366
- }, [isTargetUsable]);
367
-
368
- const recordTap = useCallback(
369
- (input: TapInput) => {
370
- if (input.cardDisabled || !input.cardEligible) return;
371
- // Tap is non-committing in drag-to-target mode regardless of whether
372
- // any usable target is currently registered. A missing target is a
373
- // composition/availability problem, not a reason to silently fall
374
- // back to tap-to-play. Hold the card in `inspecting` so the user can
375
- // see what they tapped while the runtime decides what to do next.
376
- setInspecting(input.cardId);
377
- },
378
- [setInspecting],
379
- );
380
-
381
- const recordPreviewStart = useCallback((cardId: string) => {
382
- onIntentRef.current?.({ type: "previewStart", cardId });
383
- }, []);
384
-
385
- const recordPreviewEnd = useCallback((cardId: string) => {
386
- onIntentRef.current?.({ type: "previewEnd", cardId });
387
- }, []);
388
-
389
- const recordActivate = useCallback(
390
- (cardId: string, source: "tap" | "keyboard") => {
391
- onIntentRef.current?.({ type: "activate", cardId, source });
392
- },
393
- [],
394
- );
395
-
396
- const clearInspect = useCallback(() => {
397
- if (inspectingRef.current !== null) setInspecting(null);
398
- }, [setInspecting]);
399
-
400
- const startPointerDrag = useCallback(
401
- (input: PointerDragInput): boolean => {
402
- if (activeDragRef.current) return false;
403
- if (inspectingRef.current) setInspecting(null);
404
- const overTargetId = resolveDropTarget({
405
- x: input.pointerX,
406
- y: input.pointerY,
407
- });
408
- const next: ActiveDragState = {
409
- cardId: input.cardId,
410
- cardLabel: input.cardLabel ?? null,
411
- source: "pointer",
412
- pointerId: input.pointerId,
413
- pointerX: input.pointerX,
414
- pointerY: input.pointerY,
415
- grabOffsetX: input.grabOffsetX,
416
- grabOffsetY: input.grabOffsetY,
417
- sourceRect: input.sourceRect,
418
- content: input.content,
419
- overTargetId,
420
- keyboardFocusedTargetId: null,
421
- sourceFocus: input.sourceFocus ?? null,
422
- };
423
- setActive(next);
424
- return true;
425
- },
426
- [resolveDropTarget, setActive, setInspecting],
427
- );
428
-
429
- const updatePointer = useCallback(
430
- (point: { x: number; y: number }) => {
431
- const active = activeDragRef.current;
432
- if (!active || active.source !== "pointer") return;
433
- const overTargetId = resolveDropTarget(point);
434
- setActive({
435
- ...active,
436
- pointerX: point.x,
437
- pointerY: point.y,
438
- overTargetId,
439
- });
440
- },
441
- [resolveDropTarget, setActive],
442
- );
443
-
444
- const completeWithDrop = useCallback(
445
- (
446
- active: ActiveDragState,
447
- targetId: string,
448
- releaseX: number,
449
- releaseY: number,
450
- ) => {
451
- const target = targetsRef.current.get(targetId);
452
- const targetRect = target?.element.getBoundingClientRect();
453
- const settling: SettlingState = {
454
- cardId: active.cardId,
455
- source: active.source,
456
- pointerX: releaseX,
457
- pointerY: releaseY,
458
- grabOffsetX: active.grabOffsetX,
459
- grabOffsetY: active.grabOffsetY,
460
- sourceRect: active.sourceRect,
461
- targetRect: targetRect
462
- ? {
463
- left: targetRect.left,
464
- top: targetRect.top,
465
- width: targetRect.width,
466
- height: targetRect.height,
467
- }
468
- : active.sourceRect,
469
- content: active.content,
470
- };
471
- onIntentRef.current?.({
472
- type: "drop",
473
- cardId: active.cardId,
474
- targetId,
475
- source: active.source === "keyboard" ? "keyboard" : "pointer",
476
- });
477
- setSettlingState(settling);
478
- setReturningState(null);
479
- setActive(null);
480
- finalizeInteraction(active.sourceFocus);
481
- },
482
- [finalizeInteraction, setActive],
483
- );
484
-
485
- const completeWithReturn = useCallback(
486
- (active: ActiveDragState, releaseX: number, releaseY: number) => {
487
- const returning: ReturningState = {
488
- cardId: active.cardId,
489
- source: active.source,
490
- pointerX: releaseX,
491
- pointerY: releaseY,
492
- grabOffsetX: active.grabOffsetX,
493
- grabOffsetY: active.grabOffsetY,
494
- sourceRect: active.sourceRect,
495
- content: active.content,
496
- };
497
- setReturningState(returning);
498
- setSettlingState(null);
499
- setActive(null);
500
- finalizeInteraction(active.sourceFocus);
501
- },
502
- [finalizeInteraction, setActive],
503
- );
504
-
505
- const releasePointer = useCallback(
506
- (point: { x: number; y: number }) => {
507
- const active = activeDragRef.current;
508
- if (!active || active.source !== "pointer") return;
509
- const overTargetId = resolveDropTarget(point);
510
- if (overTargetId) {
511
- completeWithDrop(active, overTargetId, point.x, point.y);
512
- return;
513
- }
514
- completeWithReturn(active, point.x, point.y);
515
- },
516
- [completeWithDrop, completeWithReturn, resolveDropTarget],
517
- );
518
-
519
- const cancelDrag = useCallback(() => {
520
- const active = activeDragRef.current;
521
- if (!active) return;
522
- completeWithReturn(active, active.pointerX, active.pointerY);
523
- }, [completeWithReturn]);
524
-
525
- const startKeyboardDrag = useCallback(
526
- (input: KeyboardDragInput): boolean => {
527
- if (activeDragRef.current) return false;
528
- if (!input.cardEligible) return false;
529
- if (inspectingRef.current) setInspecting(null);
530
- const ids = sortedUsableTargetIds();
531
- if (ids.length === 0) return false;
532
- const firstFocus = ids[0]!;
533
- const firstTarget = targetsRef.current.get(firstFocus);
534
- const firstRect = firstTarget?.element.getBoundingClientRect();
535
- const next: ActiveDragState = {
536
- cardId: input.cardId,
537
- cardLabel: input.cardLabel ?? null,
538
- source: "keyboard",
539
- pointerId: null,
540
- pointerX: firstRect ? firstRect.left + firstRect.width / 2 : 0,
541
- pointerY: firstRect ? firstRect.top + firstRect.height / 2 : 0,
542
- grabOffsetX: 0,
543
- grabOffsetY: 0,
544
- sourceRect: input.sourceRect,
545
- content: input.content,
546
- overTargetId: firstFocus,
547
- keyboardFocusedTargetId: firstFocus,
548
- sourceFocus: input.sourceFocus ?? null,
549
- };
550
- setActive(next);
551
- // Focus is moved by `CardDropTargetView` in an effect that watches
552
- // `keyboardFocusedTargetId`, ensuring focus transfer happens after
553
- // React commits the render that promotes this target.
554
- return true;
555
- },
556
- [setActive, setInspecting, sortedUsableTargetIds],
557
- );
558
-
559
- const moveKeyboardFocus = useCallback(
560
- (direction: "next" | "prev") => {
561
- const active = activeDragRef.current;
562
- if (!active || active.source !== "keyboard") return;
563
- const ids = sortedUsableTargetIds();
564
- if (ids.length === 0) return;
565
- const currentIdx = active.keyboardFocusedTargetId
566
- ? ids.indexOf(active.keyboardFocusedTargetId)
567
- : -1;
568
- const nextIdx =
569
- direction === "next"
570
- ? (currentIdx + 1) % ids.length
571
- : (currentIdx - 1 + ids.length) % ids.length;
572
- const nextId = ids[nextIdx]!;
573
- const target = targetsRef.current.get(nextId);
574
- const rect = target?.element.getBoundingClientRect();
575
- setActive({
576
- ...active,
577
- keyboardFocusedTargetId: nextId,
578
- overTargetId: nextId,
579
- pointerX: rect ? rect.left + rect.width / 2 : active.pointerX,
580
- pointerY: rect ? rect.top + rect.height / 2 : active.pointerY,
581
- });
582
- // Focus moved by the target's keyboardFocused effect.
583
- },
584
- [setActive, sortedUsableTargetIds],
585
- );
586
-
587
- const commitKeyboardDrop = useCallback(() => {
588
- const active = activeDragRef.current;
589
- if (!active || active.source !== "keyboard") return;
590
- const targetId = active.keyboardFocusedTargetId;
591
- if (!targetId) return;
592
- const target = targetsRef.current.get(targetId);
593
- if (!target || !isTargetUsable(target)) return;
594
- const rect = target.element.getBoundingClientRect();
595
- completeWithDrop(
596
- active,
597
- targetId,
598
- rect.left + rect.width / 2,
599
- rect.top + rect.height / 2,
600
- );
601
- }, [completeWithDrop, isTargetUsable]);
602
-
603
- const phase: DragPhase = useMemo(() => {
604
- if (activeDrag) return "dragging";
605
- if (settlingState) return "settling";
606
- if (returningState) return "returning";
607
- if (inspectingCardId) return "inspecting";
608
- return "idle";
609
- }, [activeDrag, inspectingCardId, returningState, settlingState]);
610
-
611
- const eligibleTargetCount = useMemo(
612
- () => sortedUsableTargetIds().length,
613
- // Recompute whenever any target patch changes — `activeDrag` is a cheap
614
- // proxy: target updates also bump the surface re-render via parent state.
615
- // eslint-disable-next-line react-hooks/exhaustive-deps
616
- [activeDrag, sortedUsableTargetIds],
617
- );
618
-
619
- const controller: CardDragSurfaceController = useMemo(
620
- () => ({
621
- activeCardId:
622
- activeDrag?.cardId ??
623
- settlingState?.cardId ??
624
- returningState?.cardId ??
625
- (inspectingCardId ? inspectingCardId : null),
626
- activeSource: activeDrag?.source ?? null,
627
- phase,
628
- overTargetId: activeDrag?.overTargetId ?? null,
629
- keyboardFocusedTargetId: activeDrag?.keyboardFocusedTargetId ?? null,
630
- startPointerDrag,
631
- updatePointer,
632
- releasePointer,
633
- cancelDrag,
634
- startKeyboardDrag,
635
- moveKeyboardFocus,
636
- commitKeyboardDrop,
637
- recordTap,
638
- recordPreviewStart,
639
- recordPreviewEnd,
640
- recordActivate,
641
- clearInspect,
642
- eligibleTargetCount,
643
- }),
644
- [
645
- activeDrag,
646
- cancelDrag,
647
- clearInspect,
648
- commitKeyboardDrop,
649
- eligibleTargetCount,
650
- inspectingCardId,
651
- moveKeyboardFocus,
652
- phase,
653
- recordActivate,
654
- recordPreviewEnd,
655
- recordPreviewStart,
656
- recordTap,
657
- releasePointer,
658
- returningState,
659
- settlingState,
660
- startKeyboardDrag,
661
- startPointerDrag,
662
- updatePointer,
663
- ],
664
- );
665
-
666
- const contextValue: CardDragSurfaceContextValue = useMemo(
667
- () => ({
668
- registerTarget,
669
- updateTarget,
670
- controller,
671
- activeCardId: controller.activeCardId,
672
- overTargetId: activeDrag?.overTargetId ?? null,
673
- dragActive: activeDrag !== null,
674
- keyboardFocusedTargetId: activeDrag?.keyboardFocusedTargetId ?? null,
675
- }),
676
- [activeDrag, controller, registerTarget, updateTarget],
677
- );
678
-
679
- useEffect(() => {
680
- if (!activeDrag) return;
681
- function onKeyDown(event: globalThis.KeyboardEvent) {
682
- if (event.key === "Escape") {
683
- event.preventDefault();
684
- cancelDrag();
685
- }
686
- }
687
- window.addEventListener("keydown", onKeyDown);
688
- return () => window.removeEventListener("keydown", onKeyDown);
689
- }, [activeDrag, cancelDrag]);
690
-
691
- const announcement = useMemo(() => {
692
- if (!activeDrag) return null;
693
- const overTarget = activeDrag.overTargetId
694
- ? targetsRef.current.get(activeDrag.overTargetId)
695
- : null;
696
- const overLabel = overTarget?.label ?? null;
697
- const cardLabel = activeDrag.cardLabel ?? "Card";
698
- if (overLabel) {
699
- return `${cardLabel} over ${overLabel}. Press Enter to drop or Escape to cancel.`;
700
- }
701
- return `${cardLabel} picked up. Move to a target or press Escape to cancel.`;
702
- }, [activeDrag]);
703
-
704
- const overlayContent = activeDrag ? (
705
- <DragOverlay session={activeDrag} reducedMotion={reducedMotion} />
706
- ) : null;
707
-
708
- const settleOverlay = settlingState ? (
709
- <SettleOverlay
710
- key={`settle-${settlingState.cardId}`}
711
- session={settlingState}
712
- transition={reducedMotion ? REDUCED_TRANSITION : settleTransition}
713
- onDone={() => setSettlingState(null)}
714
- />
715
- ) : null;
716
-
717
- const returnOverlay = returningState ? (
718
- <ReturnOverlay
719
- key={`return-${returningState.cardId}`}
720
- session={returningState}
721
- transition={reducedMotion ? REDUCED_TRANSITION : returnTransition}
722
- onDone={() => setReturningState(null)}
723
- />
724
- ) : null;
725
-
726
- const portalRoot = typeof document !== "undefined" ? document.body : null;
727
-
728
- return (
729
- <CardDragSurfaceContext.Provider value={contextValue}>
730
- <div
731
- data-dreamboard-card-drag-surface=""
732
- data-drag-active={activeDrag ? "true" : undefined}
733
- data-drag-source={activeDrag?.source}
734
- data-drag-phase={phase}
735
- className={clsx("relative", className)}
736
- style={style}
737
- >
738
- {children}
739
- </div>
740
- {portalRoot
741
- ? createPortal(
742
- <AnimatePresence initial={false}>
743
- {overlayContent}
744
- {settleOverlay}
745
- {returnOverlay}
746
- </AnimatePresence>,
747
- portalRoot,
748
- )
749
- : null}
750
- {!suppressLiveAnnouncement ? (
751
- <div
752
- id={liveRegionId}
753
- role="status"
754
- aria-live="polite"
755
- className="sr-only"
756
- data-dreamboard-card-drag-announcement=""
757
- style={{
758
- position: "absolute",
759
- width: 1,
760
- height: 1,
761
- padding: 0,
762
- margin: -1,
763
- overflow: "hidden",
764
- clip: "rect(0,0,0,0)",
765
- whiteSpace: "nowrap",
766
- border: 0,
767
- }}
768
- >
769
- {announcement ?? ""}
770
- </div>
771
- ) : null}
772
- </CardDragSurfaceContext.Provider>
773
- );
774
- }
775
-
776
- interface DragOverlayProps {
777
- session: ActiveDragState;
778
- reducedMotion: boolean;
779
- }
780
-
781
- function DragOverlay({ session, reducedMotion }: DragOverlayProps) {
782
- if (session.source === "keyboard") {
783
- return (
784
- <motion.div
785
- key="overlay-keyboard"
786
- data-dreamboard-card-drag-overlay=""
787
- data-source="keyboard"
788
- initial={{ opacity: 0 }}
789
- animate={{ opacity: 1 }}
790
- exit={{ opacity: 0 }}
791
- transition={reducedMotion ? REDUCED_TRANSITION : { duration: 0.12 }}
792
- style={{
793
- position: "fixed",
794
- left: session.sourceRect.left,
795
- top: session.sourceRect.top,
796
- width: session.sourceRect.width,
797
- height: session.sourceRect.height,
798
- pointerEvents: "none",
799
- zIndex: 1000,
800
- boxShadow: reducedMotion ? "none" : "0 12px 32px rgba(0,0,0,0.18)",
801
- borderRadius: 12,
802
- }}
803
- >
804
- {session.content}
805
- </motion.div>
806
- );
807
- }
808
-
809
- const liftedAnimate = reducedMotion
810
- ? {
811
- scale: 1,
812
- rotate: 0,
813
- filter: "drop-shadow(0 0 0 rgba(0,0,0,0))",
814
- }
815
- : {
816
- scale: [1, 1.42, 1.35],
817
- rotate: [0, -3, 3, -1.8, 1.8, 0],
818
- filter: [
819
- "drop-shadow(0 4px 8px rgba(0,0,0,0.18))",
820
- "drop-shadow(0 24px 36px rgba(0,0,0,0.36))",
821
- ],
822
- };
823
- const liftedTransition: Transition = reducedMotion
824
- ? REDUCED_TRANSITION
825
- : {
826
- scale: { type: "spring", stiffness: 420, damping: 22, mass: 0.7 },
827
- rotate: { duration: 0.55, ease: "easeInOut" },
828
- filter: { duration: 0.18, ease: "easeOut" },
829
- };
830
- return (
831
- <motion.div
832
- key="overlay-pointer"
833
- data-dreamboard-card-drag-overlay=""
834
- data-source="pointer"
835
- initial={{
836
- scale: 1,
837
- rotate: 0,
838
- opacity: 1,
839
- filter: "drop-shadow(0 2px 6px rgba(0,0,0,0.15))",
840
- }}
841
- animate={liftedAnimate}
842
- exit={{ opacity: 0 }}
843
- transition={liftedTransition}
844
- style={{
845
- position: "fixed",
846
- left: session.pointerX - session.sourceRect.width / 2,
847
- top: session.pointerY - session.sourceRect.height / 2,
848
- width: session.sourceRect.width,
849
- height: session.sourceRect.height,
850
- zIndex: 1000,
851
- pointerEvents: "none",
852
- touchAction: "none",
853
- transformOrigin: "center center",
854
- willChange: "transform, filter",
855
- }}
856
- >
857
- {session.content}
858
- </motion.div>
859
- );
860
- }
861
-
862
- interface SettleOverlayProps {
863
- session: SettlingState;
864
- transition: Transition;
865
- onDone: () => void;
866
- }
867
-
868
- function SettleOverlay({ session, transition, onDone }: SettleOverlayProps) {
869
- const startLeft = session.pointerX - session.sourceRect.width / 2;
870
- const startTop = session.pointerY - session.sourceRect.height / 2;
871
- const endLeft =
872
- session.targetRect.left +
873
- session.targetRect.width / 2 -
874
- session.sourceRect.width / 2;
875
- const endTop =
876
- session.targetRect.top +
877
- session.targetRect.height / 2 -
878
- session.sourceRect.height / 2;
879
- return (
880
- <motion.div
881
- data-dreamboard-card-drag-overlay=""
882
- data-source={session.source}
883
- data-drag-phase="settling"
884
- initial={{ left: startLeft, top: startTop, scale: 1.06, opacity: 1 }}
885
- animate={{ left: endLeft, top: endTop, scale: 0.92, opacity: 0 }}
886
- transition={transition}
887
- onAnimationComplete={onDone}
888
- style={{
889
- position: "fixed",
890
- width: session.sourceRect.width,
891
- height: session.sourceRect.height,
892
- zIndex: 1000,
893
- pointerEvents: "none",
894
- }}
895
- >
896
- {session.content}
897
- </motion.div>
898
- );
899
- }
900
-
901
- interface ReturnOverlayProps {
902
- session: ReturningState;
903
- transition: Transition;
904
- onDone: () => void;
905
- }
906
-
907
- function ReturnOverlay({ session, transition, onDone }: ReturnOverlayProps) {
908
- const startLeft = session.pointerX - session.sourceRect.width / 2;
909
- const startTop = session.pointerY - session.sourceRect.height / 2;
910
- return (
911
- <motion.div
912
- data-dreamboard-card-drag-overlay=""
913
- data-source={session.source}
914
- data-drag-phase="returning"
915
- initial={{ left: startLeft, top: startTop, scale: 1.06, opacity: 1 }}
916
- animate={{
917
- left: session.sourceRect.left,
918
- top: session.sourceRect.top,
919
- scale: 1,
920
- opacity: 1,
921
- }}
922
- exit={{ opacity: 0 }}
923
- transition={transition}
924
- onAnimationComplete={onDone}
925
- style={{
926
- position: "fixed",
927
- width: session.sourceRect.width,
928
- height: session.sourceRect.height,
929
- zIndex: 1000,
930
- pointerEvents: "none",
931
- }}
932
- >
933
- {session.content}
934
- </motion.div>
935
- );
936
- }
937
-
938
- export interface CardDropTargetViewProps {
939
- targetId: string;
940
- state?: CardDropTargetVisualState;
941
- /** Plain-text label used in live announcements ("Selected cards", etc.). */
942
- label?: string;
943
- renderTarget: (state: CardDropTargetVisualState) => ReactNode;
944
- className?: string;
945
- style?: CSSProperties;
946
- /** Tab order hint (lower numbers focus first). */
947
- order?: number;
948
- /** ARIA role override; defaults to `button`. */
949
- role?: string;
950
- }
951
-
952
- export function CardDropTargetView({
953
- targetId,
954
- state,
955
- label,
956
- renderTarget,
957
- className,
958
- style,
959
- order,
960
- role = "button",
961
- }: CardDropTargetViewProps) {
962
- const surface = useCardDragSurface();
963
- const ref = useRef<HTMLDivElement | null>(null);
964
- const disabled = state?.disabled ?? false;
965
- const baseEligible = state?.eligible ?? true;
966
- const baseLabel = label ?? null;
967
- const orderProp = order ?? 0;
968
-
969
- const registerTargetRef = useRef(surface?.registerTarget);
970
- registerTargetRef.current = surface?.registerTarget;
971
- const updateTargetRef = useRef(surface?.updateTarget);
972
- updateTargetRef.current = surface?.updateTarget;
973
-
974
- // Stable register/unregister keyed only on `targetId`. Eligibility, label
975
- // and disabled flow through `updateTarget` so changing surface context
976
- // values cannot tear down the registration mid-drag.
977
- useEffect(() => {
978
- const element = ref.current;
979
- const register = registerTargetRef.current;
980
- if (!register || !element) return;
981
- const unregister = register({
982
- targetId,
983
- disabled,
984
- eligible: baseEligible,
985
- element,
986
- label: baseLabel,
987
- order: orderProp,
988
- });
989
- return unregister;
990
- // eslint-disable-next-line react-hooks/exhaustive-deps
991
- }, [targetId]);
992
-
993
- useEffect(() => {
994
- updateTargetRef.current?.(targetId, {
995
- disabled,
996
- eligible: baseEligible,
997
- label: baseLabel,
998
- order: orderProp,
999
- });
1000
- }, [targetId, disabled, baseEligible, baseLabel, orderProp]);
1001
-
1002
- const dragActive = surface?.dragActive ?? false;
1003
- const overTargetId = surface?.overTargetId ?? null;
1004
- const keyboardFocused = surface?.keyboardFocusedTargetId === targetId;
1005
-
1006
- // Move focus into this target whenever the surface promotes it to the
1007
- // keyboard-focused id. Doing it here, after React commits, is more
1008
- // reliable than firing focus() from inside the surface's `setActive`
1009
- // callback (where React batching can race the source card's commit).
1010
- useEffect(() => {
1011
- if (!keyboardFocused) return;
1012
- const el = ref.current;
1013
- if (!el) return;
1014
- if (document.activeElement === el) return;
1015
- try {
1016
- el.focus({ preventScroll: true });
1017
- } catch {
1018
- // Element may have unmounted; ignore.
1019
- }
1020
- }, [keyboardFocused, targetId]);
1021
-
1022
- const computedState: CardDropTargetVisualState = {
1023
- ...state,
1024
- eligible: baseEligible,
1025
- active: dragActive ? true : state?.active,
1026
- over:
1027
- overTargetId === targetId && baseEligible ? true : (state?.over ?? false),
1028
- };
1029
-
1030
- const handleKeyDown = useCallback(
1031
- (event: KeyboardEvent<HTMLDivElement>) => {
1032
- if (!surface) return;
1033
- const controller = surface.controller;
1034
- if (controller.activeSource !== "keyboard") return;
1035
- if (event.key === "Enter" || event.key === " ") {
1036
- event.preventDefault();
1037
- controller.commitKeyboardDrop();
1038
- return;
1039
- }
1040
- if (event.key === "ArrowRight" || event.key === "ArrowDown") {
1041
- event.preventDefault();
1042
- controller.moveKeyboardFocus("next");
1043
- return;
1044
- }
1045
- if (event.key === "ArrowLeft" || event.key === "ArrowUp") {
1046
- event.preventDefault();
1047
- controller.moveKeyboardFocus("prev");
1048
- return;
1049
- }
1050
- if (event.key === "Escape") {
1051
- event.preventDefault();
1052
- controller.cancelDrag();
1053
- }
1054
- },
1055
- [surface],
1056
- );
1057
-
1058
- return (
1059
- <div
1060
- ref={ref}
1061
- data-dreamboard-card-drop-target=""
1062
- data-target-id={targetId}
1063
- data-keyboard-focused={keyboardFocused ? "true" : undefined}
1064
- role={role}
1065
- tabIndex={disabled || !baseEligible ? -1 : 0}
1066
- aria-disabled={disabled || !baseEligible || undefined}
1067
- aria-label={label}
1068
- onKeyDown={handleKeyDown}
1069
- className={className}
1070
- style={style}
1071
- {...dropTargetVisualStateDataAttributes(computedState)}
1072
- >
1073
- {renderTarget(computedState)}
1074
- </div>
1075
- );
1076
- }