@ankhorage/zora 21.0.22 → 21.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (639) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +40 -184
  3. package/dist/features/authoring/allowedChildren.d.ts +5 -2
  4. package/dist/features/authoring/allowedChildren.d.ts.map +1 -1
  5. package/dist/features/authoring/allowedChildren.js +13 -2
  6. package/dist/features/authoring/allowedChildren.js.map +1 -1
  7. package/dist/features/authoring/componentMeta.d.ts.map +1 -1
  8. package/dist/features/authoring/componentMeta.js +21 -0
  9. package/dist/features/authoring/componentMeta.js.map +1 -1
  10. package/dist/features/authoring/constants.d.ts +3 -0
  11. package/dist/features/authoring/constants.d.ts.map +1 -1
  12. package/dist/features/authoring/constants.js +3 -0
  13. package/dist/features/authoring/constants.js.map +1 -1
  14. package/dist/features/button/adapters/inbound/Button.d.ts +0 -4
  15. package/dist/features/button/adapters/inbound/Button.d.ts.map +1 -1
  16. package/dist/features/button/adapters/inbound/Button.js +0 -4
  17. package/dist/features/button/adapters/inbound/Button.js.map +1 -1
  18. package/dist/features/card/adapters/inbound/Card.d.ts +0 -4
  19. package/dist/features/card/adapters/inbound/Card.d.ts.map +1 -1
  20. package/dist/features/card/adapters/inbound/Card.js +0 -4
  21. package/dist/features/card/adapters/inbound/Card.js.map +1 -1
  22. package/dist/features/card/cardMeta.d.ts +1 -1
  23. package/dist/features/card/cardMeta.d.ts.map +1 -1
  24. package/dist/features/card/cardMeta.js +7 -2
  25. package/dist/features/card/cardMeta.js.map +1 -1
  26. package/dist/features/chess/adapters/inbound/ChessBoard.d.ts +5 -0
  27. package/dist/features/chess/adapters/inbound/ChessBoard.d.ts.map +1 -0
  28. package/dist/features/chess/adapters/inbound/ChessBoard.js +119 -0
  29. package/dist/features/chess/adapters/inbound/ChessBoard.js.map +1 -0
  30. package/dist/features/chess/adapters/inbound/OpeningBook.d.ts +5 -0
  31. package/dist/features/chess/adapters/inbound/OpeningBook.d.ts.map +1 -0
  32. package/dist/features/chess/adapters/inbound/OpeningBook.js +94 -0
  33. package/dist/features/chess/adapters/inbound/OpeningBook.js.map +1 -0
  34. package/dist/features/chess/meta.d.ts +219 -0
  35. package/dist/features/chess/meta.d.ts.map +1 -0
  36. package/dist/features/chess/meta.js +165 -0
  37. package/dist/features/chess/meta.js.map +1 -0
  38. package/dist/features/chess/public.d.ts +12 -0
  39. package/dist/features/chess/public.d.ts.map +1 -0
  40. package/dist/features/chess/public.js +10 -0
  41. package/dist/features/chess/public.js.map +1 -0
  42. package/dist/features/chess/utils/chessSquares.d.ts +4 -0
  43. package/dist/features/chess/utils/chessSquares.d.ts.map +1 -0
  44. package/dist/features/chess/utils/chessSquares.js +3 -0
  45. package/dist/features/chess/utils/chessSquares.js.map +1 -0
  46. package/dist/features/chess/utils/createBoardSquares.d.ts +4 -0
  47. package/dist/features/chess/utils/createBoardSquares.d.ts.map +1 -0
  48. package/dist/features/chess/utils/createBoardSquares.js +9 -0
  49. package/dist/features/chess/utils/createBoardSquares.js.map +1 -0
  50. package/dist/features/chess/utils/createChessBoardColorScheme.d.ts +35 -0
  51. package/dist/features/chess/utils/createChessBoardColorScheme.d.ts.map +1 -0
  52. package/dist/features/chess/utils/createChessBoardColorScheme.js +26 -0
  53. package/dist/features/chess/utils/createChessBoardColorScheme.js.map +1 -0
  54. package/dist/features/chess/utils/createOpeningBookColorScheme.d.ts +11 -0
  55. package/dist/features/chess/utils/createOpeningBookColorScheme.d.ts.map +1 -0
  56. package/dist/features/chess/utils/createOpeningBookColorScheme.js +21 -0
  57. package/dist/features/chess/utils/createOpeningBookColorScheme.js.map +1 -0
  58. package/dist/features/chess/utils/getSquareFile.d.ts +4 -0
  59. package/dist/features/chess/utils/getSquareFile.d.ts.map +1 -0
  60. package/dist/features/chess/utils/getSquareFile.js +5 -0
  61. package/dist/features/chess/utils/getSquareFile.js.map +1 -0
  62. package/dist/features/chess/utils/getSquareRank.d.ts +4 -0
  63. package/dist/features/chess/utils/getSquareRank.d.ts.map +1 -0
  64. package/dist/features/chess/utils/getSquareRank.js +5 -0
  65. package/dist/features/chess/utils/getSquareRank.js.map +1 -0
  66. package/dist/features/chess/utils/isLightSquare.d.ts +4 -0
  67. package/dist/features/chess/utils/isLightSquare.d.ts.map +1 -0
  68. package/dist/features/chess/utils/isLightSquare.js +6 -0
  69. package/dist/features/chess/utils/isLightSquare.js.map +1 -0
  70. package/dist/features/empty-state/adapters/inbound/EmptyState.d.ts +0 -4
  71. package/dist/features/empty-state/adapters/inbound/EmptyState.d.ts.map +1 -1
  72. package/dist/features/empty-state/adapters/inbound/EmptyState.js +0 -4
  73. package/dist/features/empty-state/adapters/inbound/EmptyState.js.map +1 -1
  74. package/dist/features/form/text-input/adapters/inbound/TextInput.d.ts +0 -4
  75. package/dist/features/form/text-input/adapters/inbound/TextInput.d.ts.map +1 -1
  76. package/dist/features/form/text-input/adapters/inbound/TextInput.js +0 -4
  77. package/dist/features/form/text-input/adapters/inbound/TextInput.js.map +1 -1
  78. package/dist/features/game/adapters/inbound/Game.d.ts +5 -0
  79. package/dist/features/game/adapters/inbound/Game.d.ts.map +1 -0
  80. package/dist/features/game/adapters/inbound/Game.js +24 -0
  81. package/dist/features/game/adapters/inbound/Game.js.map +1 -0
  82. package/dist/features/game/adapters/inbound/GameEntity.d.ts +5 -0
  83. package/dist/features/game/adapters/inbound/GameEntity.d.ts.map +1 -0
  84. package/dist/features/game/adapters/inbound/GameEntity.js +29 -0
  85. package/dist/features/game/adapters/inbound/GameEntity.js.map +1 -0
  86. package/dist/features/game/adapters/inbound/GameField.d.ts +4 -0
  87. package/dist/features/game/adapters/inbound/GameField.d.ts.map +1 -0
  88. package/dist/features/game/adapters/inbound/GameField.js +32 -0
  89. package/dist/features/game/adapters/inbound/GameField.js.map +1 -0
  90. package/dist/features/game/adapters/inbound/GameInputZone.d.ts +4 -0
  91. package/dist/features/game/adapters/inbound/GameInputZone.d.ts.map +1 -0
  92. package/dist/features/game/adapters/inbound/GameInputZone.js +50 -0
  93. package/dist/features/game/adapters/inbound/GameInputZone.js.map +1 -0
  94. package/dist/features/game/adapters/inbound/GameMeasurementProbe.d.ts +4 -0
  95. package/dist/features/game/adapters/inbound/GameMeasurementProbe.d.ts.map +1 -0
  96. package/dist/features/game/adapters/inbound/GameMeasurementProbe.js +54 -0
  97. package/dist/features/game/adapters/inbound/GameMeasurementProbe.js.map +1 -0
  98. package/dist/features/game/adapters/inbound/GameOverlay.d.ts +4 -0
  99. package/dist/features/game/adapters/inbound/GameOverlay.d.ts.map +1 -0
  100. package/dist/features/game/adapters/inbound/GameOverlay.js +39 -0
  101. package/dist/features/game/adapters/inbound/GameOverlay.js.map +1 -0
  102. package/dist/features/game/adapters/inbound/createGameKeyboardEvent.d.ts +16 -0
  103. package/dist/features/game/adapters/inbound/createGameKeyboardEvent.d.ts.map +1 -0
  104. package/dist/features/game/adapters/inbound/createGameKeyboardEvent.js +16 -0
  105. package/dist/features/game/adapters/inbound/createGameKeyboardEvent.js.map +1 -0
  106. package/dist/features/game/adapters/inbound/createGameMeasurementEvent.d.ts +14 -0
  107. package/dist/features/game/adapters/inbound/createGameMeasurementEvent.d.ts.map +1 -0
  108. package/dist/features/game/adapters/inbound/createGameMeasurementEvent.js +25 -0
  109. package/dist/features/game/adapters/inbound/createGameMeasurementEvent.js.map +1 -0
  110. package/dist/features/game/adapters/inbound/createGamePointerEvent.d.ts +17 -0
  111. package/dist/features/game/adapters/inbound/createGamePointerEvent.d.ts.map +1 -0
  112. package/dist/features/game/adapters/inbound/createGamePointerEvent.js +20 -0
  113. package/dist/features/game/adapters/inbound/createGamePointerEvent.js.map +1 -0
  114. package/dist/features/game/adapters/inbound/measureGameEntity.d.ts +5 -0
  115. package/dist/features/game/adapters/inbound/measureGameEntity.d.ts.map +1 -0
  116. package/dist/features/game/adapters/inbound/measureGameEntity.js +22 -0
  117. package/dist/features/game/adapters/inbound/measureGameEntity.js.map +1 -0
  118. package/dist/features/game/adapters/inbound/useGameInputZoneResponder.d.ts +15 -0
  119. package/dist/features/game/adapters/inbound/useGameInputZoneResponder.d.ts.map +1 -0
  120. package/dist/features/game/adapters/inbound/useGameInputZoneResponder.js +67 -0
  121. package/dist/features/game/adapters/inbound/useGameInputZoneResponder.js.map +1 -0
  122. package/dist/features/game/composition/GameRuntimeContext.d.ts +5 -0
  123. package/dist/features/game/composition/GameRuntimeContext.d.ts.map +1 -0
  124. package/dist/features/game/composition/GameRuntimeContext.js +4 -0
  125. package/dist/features/game/composition/GameRuntimeContext.js.map +1 -0
  126. package/dist/features/game/composition/createGameBindingContext.d.ts +4 -0
  127. package/dist/features/game/composition/createGameBindingContext.d.ts.map +1 -0
  128. package/dist/features/game/composition/createGameBindingContext.js +10 -0
  129. package/dist/features/game/composition/createGameBindingContext.js.map +1 -0
  130. package/dist/features/game/composition/createGameMeasurementRegistry.d.ts +4 -0
  131. package/dist/features/game/composition/createGameMeasurementRegistry.d.ts.map +1 -0
  132. package/dist/features/game/composition/createGameMeasurementRegistry.js +15 -0
  133. package/dist/features/game/composition/createGameMeasurementRegistry.js.map +1 -0
  134. package/dist/features/game/composition/useGameRuntime.d.ts +5 -0
  135. package/dist/features/game/composition/useGameRuntime.d.ts.map +1 -0
  136. package/dist/features/game/composition/useGameRuntime.js +117 -0
  137. package/dist/features/game/composition/useGameRuntime.js.map +1 -0
  138. package/dist/features/game/composition/useGameScheduledEffects.d.ts +17 -0
  139. package/dist/features/game/composition/useGameScheduledEffects.d.ts.map +1 -0
  140. package/dist/features/game/composition/useGameScheduledEffects.js +40 -0
  141. package/dist/features/game/composition/useGameScheduledEffects.js.map +1 -0
  142. package/dist/features/game/meta/gameEntityMeta.d.ts +403 -0
  143. package/dist/features/game/meta/gameEntityMeta.d.ts.map +1 -0
  144. package/dist/features/game/meta/gameEntityMeta.js +224 -0
  145. package/dist/features/game/meta/gameEntityMeta.js.map +1 -0
  146. package/dist/features/game/meta/gameFieldMeta.d.ts +61 -0
  147. package/dist/features/game/meta/gameFieldMeta.d.ts.map +1 -0
  148. package/dist/features/game/meta/gameFieldMeta.js +48 -0
  149. package/dist/features/game/meta/gameFieldMeta.js.map +1 -0
  150. package/dist/features/game/meta/gameInputZoneMeta.d.ts +163 -0
  151. package/dist/features/game/meta/gameInputZoneMeta.d.ts.map +1 -0
  152. package/dist/features/game/meta/gameInputZoneMeta.js +138 -0
  153. package/dist/features/game/meta/gameInputZoneMeta.js.map +1 -0
  154. package/dist/features/game/meta/gameMeasurementProbeMeta.d.ts +112 -0
  155. package/dist/features/game/meta/gameMeasurementProbeMeta.d.ts.map +1 -0
  156. package/dist/features/game/meta/gameMeasurementProbeMeta.js +70 -0
  157. package/dist/features/game/meta/gameMeasurementProbeMeta.js.map +1 -0
  158. package/dist/features/game/meta/gameMeta.d.ts +130 -0
  159. package/dist/features/game/meta/gameMeta.d.ts.map +1 -0
  160. package/dist/features/game/meta/gameMeta.js +113 -0
  161. package/dist/features/game/meta/gameMeta.js.map +1 -0
  162. package/dist/features/game/meta/gameOverlayMeta.d.ts +55 -0
  163. package/dist/features/game/meta/gameOverlayMeta.d.ts.map +1 -0
  164. package/dist/features/game/meta/gameOverlayMeta.js +65 -0
  165. package/dist/features/game/meta/gameOverlayMeta.js.map +1 -0
  166. package/dist/features/game/public.d.ts +8 -0
  167. package/dist/features/game/public.d.ts.map +1 -0
  168. package/dist/features/game/public.js +7 -0
  169. package/dist/features/game/public.js.map +1 -0
  170. package/dist/features/game/utils/clampGamePercentage.d.ts +3 -0
  171. package/dist/features/game/utils/clampGamePercentage.d.ts.map +1 -0
  172. package/dist/features/game/utils/clampGamePercentage.js +5 -0
  173. package/dist/features/game/utils/clampGamePercentage.js.map +1 -0
  174. package/dist/features/game/utils/resolveGameEntityMotionPlan.d.ts +15 -0
  175. package/dist/features/game/utils/resolveGameEntityMotionPlan.d.ts.map +1 -0
  176. package/dist/features/game/utils/resolveGameEntityMotionPlan.js +31 -0
  177. package/dist/features/game/utils/resolveGameEntityMotionPlan.js.map +1 -0
  178. package/dist/features/game/utils/toGamePercentage.d.ts +3 -0
  179. package/dist/features/game/utils/toGamePercentage.d.ts.map +1 -0
  180. package/dist/features/game/utils/toGamePercentage.js +6 -0
  181. package/dist/features/game/utils/toGamePercentage.js.map +1 -0
  182. package/dist/features/game/utils/useAnimatedGameEntityValue.d.ts +5 -0
  183. package/dist/features/game/utils/useAnimatedGameEntityValue.d.ts.map +1 -0
  184. package/dist/features/game/utils/useAnimatedGameEntityValue.js +33 -0
  185. package/dist/features/game/utils/useAnimatedGameEntityValue.js.map +1 -0
  186. package/dist/features/game/utils/useGameEntityAnimatedStyle.d.ts +16 -0
  187. package/dist/features/game/utils/useGameEntityAnimatedStyle.d.ts.map +1 -0
  188. package/dist/features/game/utils/useGameEntityAnimatedStyle.js +52 -0
  189. package/dist/features/game/utils/useGameEntityAnimatedStyle.js.map +1 -0
  190. package/dist/features/game/utils/useGameEntityMeasurement.d.ts +5 -0
  191. package/dist/features/game/utils/useGameEntityMeasurement.d.ts.map +1 -0
  192. package/dist/features/game/utils/useGameEntityMeasurement.js +14 -0
  193. package/dist/features/game/utils/useGameEntityMeasurement.js.map +1 -0
  194. package/dist/features/game/utils/useGameEntityMotionProgress.d.ts +5 -0
  195. package/dist/features/game/utils/useGameEntityMotionProgress.d.ts.map +1 -0
  196. package/dist/features/game/utils/useGameEntityMotionProgress.js +87 -0
  197. package/dist/features/game/utils/useGameEntityMotionProgress.js.map +1 -0
  198. package/dist/features/game/utils/useGameReducedMotion.d.ts +3 -0
  199. package/dist/features/game/utils/useGameReducedMotion.d.ts.map +1 -0
  200. package/dist/features/game/utils/useGameReducedMotion.js +13 -0
  201. package/dist/features/game/utils/useGameReducedMotion.js.map +1 -0
  202. package/dist/features/graph-view/adapters/inbound/web-artifact/GraphView.d.ts +5 -5
  203. package/dist/features/graph-view/adapters/inbound/web-artifact/GraphView.js +5 -5
  204. package/dist/features/graph-view/adapters/inbound/web-artifact/GraphView.js.map +1 -1
  205. package/dist/features/graph-view/adapters/inbound/web-artifact/compactGraphSpacing.d.ts +1 -1
  206. package/dist/features/graph-view/adapters/inbound/web-artifact/compactGraphSpacing.js +1 -1
  207. package/dist/features/graph-view/adapters/inbound/web-artifact/compactGraphSpacing.js.map +1 -1
  208. package/dist/features/graph-view/adapters/inbound/web-artifact/createGraphController.js +1 -1
  209. package/dist/features/graph-view/adapters/inbound/web-artifact/createGraphController.js.map +1 -1
  210. package/dist/features/graph-view/adapters/inbound/web-artifact/createGraphLoopSizer.d.ts +1 -1
  211. package/dist/features/graph-view/adapters/inbound/web-artifact/createGraphLoopSizer.js +1 -1
  212. package/dist/features/graph-view/adapters/inbound/web-artifact/createGraphLoopSizer.js.map +1 -1
  213. package/dist/features/graph-view/adapters/inbound/web-artifact/createGraphRuntime.js +7 -7
  214. package/dist/features/graph-view/adapters/inbound/web-artifact/createGraphRuntime.js.map +1 -1
  215. package/dist/features/graph-view/adapters/inbound/web-artifact/getGraphGeometryKey.d.ts +0 -1
  216. package/dist/features/graph-view/adapters/inbound/web-artifact/getGraphGeometryKey.d.ts.map +1 -1
  217. package/dist/features/graph-view/adapters/inbound/web-artifact/getGraphGeometryKey.js +0 -1
  218. package/dist/features/graph-view/adapters/inbound/web-artifact/getGraphGeometryKey.js.map +1 -1
  219. package/dist/features/graph-view/adapters/inbound/web-artifact/getGraphTopologyKey.d.ts +1 -1
  220. package/dist/features/graph-view/adapters/inbound/web-artifact/getGraphTopologyKey.js +1 -1
  221. package/dist/features/graph-view/adapters/inbound/web-artifact/getGraphTopologyKey.js.map +1 -1
  222. package/dist/features/graph-view/adapters/inbound/web-artifact/hasGraphLayoutChanged.d.ts +0 -1
  223. package/dist/features/graph-view/adapters/inbound/web-artifact/hasGraphLayoutChanged.d.ts.map +1 -1
  224. package/dist/features/graph-view/adapters/inbound/web-artifact/hasGraphLayoutChanged.js +0 -1
  225. package/dist/features/graph-view/adapters/inbound/web-artifact/hasGraphLayoutChanged.js.map +1 -1
  226. package/dist/features/graph-view/adapters/inbound/web-artifact/runDetachedGraphLayout.d.ts +1 -1
  227. package/dist/features/graph-view/adapters/inbound/web-artifact/runDetachedGraphLayout.js +1 -1
  228. package/dist/features/graph-view/adapters/inbound/web-artifact/runDetachedGraphLayout.js.map +1 -1
  229. package/dist/features/graph-view/adapters/inbound/web-artifact/sizeGraphNodesToLabels.d.ts +1 -1
  230. package/dist/features/graph-view/adapters/inbound/web-artifact/sizeGraphNodesToLabels.js +1 -1
  231. package/dist/features/graph-view/adapters/inbound/web-artifact/sizeGraphNodesToLabels.js.map +1 -1
  232. package/dist/features/graph-view/adapters/inbound/web-artifact/syncGraphElements.d.ts +0 -1
  233. package/dist/features/graph-view/adapters/inbound/web-artifact/syncGraphElements.d.ts.map +1 -1
  234. package/dist/features/graph-view/adapters/inbound/web-artifact/syncGraphElements.js +0 -1
  235. package/dist/features/graph-view/adapters/inbound/web-artifact/syncGraphElements.js.map +1 -1
  236. package/dist/features/layout/gridMeta.d.ts +1 -1
  237. package/dist/features/layout/gridMeta.d.ts.map +1 -1
  238. package/dist/features/layout/gridMeta.js +7 -2
  239. package/dist/features/layout/gridMeta.js.map +1 -1
  240. package/dist/features/layout/screenMeta.d.ts +1 -1
  241. package/dist/features/layout/viewMeta.d.ts +1 -1
  242. package/dist/features/layout/viewMeta.d.ts.map +1 -1
  243. package/dist/features/layout/viewMeta.js +6 -2
  244. package/dist/features/layout/viewMeta.js.map +1 -1
  245. package/dist/features/registry/ZORA_COMPONENT_REGISTRY.d.ts.map +1 -1
  246. package/dist/features/registry/ZORA_COMPONENT_REGISTRY.js +16 -0
  247. package/dist/features/registry/ZORA_COMPONENT_REGISTRY.js.map +1 -1
  248. package/dist/features/section/screenSectionMeta.d.ts +1 -1
  249. package/dist/features/tabletop/adapters/inbound/CardBack.d.ts +5 -0
  250. package/dist/features/tabletop/adapters/inbound/CardBack.d.ts.map +1 -0
  251. package/dist/features/tabletop/adapters/inbound/CardBack.js +47 -0
  252. package/dist/features/tabletop/adapters/inbound/CardBack.js.map +1 -0
  253. package/dist/features/tabletop/adapters/inbound/CardHand.d.ts +5 -0
  254. package/dist/features/tabletop/adapters/inbound/CardHand.d.ts.map +1 -0
  255. package/dist/features/tabletop/adapters/inbound/CardHand.js +28 -0
  256. package/dist/features/tabletop/adapters/inbound/CardHand.js.map +1 -0
  257. package/dist/features/tabletop/adapters/inbound/PlayingCard.d.ts +5 -0
  258. package/dist/features/tabletop/adapters/inbound/PlayingCard.d.ts.map +1 -0
  259. package/dist/features/tabletop/adapters/inbound/PlayingCard.js +64 -0
  260. package/dist/features/tabletop/adapters/inbound/PlayingCard.js.map +1 -0
  261. package/dist/features/tabletop/adapters/inbound/PokerTrainingTable.d.ts +5 -0
  262. package/dist/features/tabletop/adapters/inbound/PokerTrainingTable.d.ts.map +1 -0
  263. package/dist/features/tabletop/adapters/inbound/PokerTrainingTable.js +12 -0
  264. package/dist/features/tabletop/adapters/inbound/PokerTrainingTable.js.map +1 -0
  265. package/dist/features/tabletop/adapters/inbound/TabletopTable.d.ts +5 -0
  266. package/dist/features/tabletop/adapters/inbound/TabletopTable.d.ts.map +1 -0
  267. package/dist/features/tabletop/adapters/inbound/TabletopTable.js +206 -0
  268. package/dist/features/tabletop/adapters/inbound/TabletopTable.js.map +1 -0
  269. package/dist/features/tabletop/meta.d.ts +353 -0
  270. package/dist/features/tabletop/meta.d.ts.map +1 -0
  271. package/dist/features/tabletop/meta.js +252 -0
  272. package/dist/features/tabletop/meta.js.map +1 -0
  273. package/dist/features/tabletop/public.d.ts +10 -0
  274. package/dist/features/tabletop/public.d.ts.map +1 -0
  275. package/dist/features/tabletop/public.js +9 -0
  276. package/dist/features/tabletop/public.js.map +1 -0
  277. package/dist/features/tabletop/utils/createPokerTrainingTableState.d.ts +13 -0
  278. package/dist/features/tabletop/utils/createPokerTrainingTableState.d.ts.map +1 -0
  279. package/dist/features/tabletop/utils/createPokerTrainingTableState.js +112 -0
  280. package/dist/features/tabletop/utils/createPokerTrainingTableState.js.map +1 -0
  281. package/dist/features/tabletop/utils/createTabletopColorScheme.d.ts +36 -0
  282. package/dist/features/tabletop/utils/createTabletopColorScheme.d.ts.map +1 -0
  283. package/dist/features/tabletop/utils/createTabletopColorScheme.js +144 -0
  284. package/dist/features/tabletop/utils/createTabletopColorScheme.js.map +1 -0
  285. package/dist/features/tabletop/utils/createTabletopGameSeats.d.ts +13 -0
  286. package/dist/features/tabletop/utils/createTabletopGameSeats.d.ts.map +1 -0
  287. package/dist/features/tabletop/utils/createTabletopGameSeats.js +22 -0
  288. package/dist/features/tabletop/utils/createTabletopGameSeats.js.map +1 -0
  289. package/dist/features/tabletop/utils/getPlayingCardLabel.d.ts +4 -0
  290. package/dist/features/tabletop/utils/getPlayingCardLabel.d.ts.map +1 -0
  291. package/dist/features/tabletop/utils/getPlayingCardLabel.js +6 -0
  292. package/dist/features/tabletop/utils/getPlayingCardLabel.js.map +1 -0
  293. package/dist/features/tabletop/utils/getTabletopCardDimensions.d.ts +12 -0
  294. package/dist/features/tabletop/utils/getTabletopCardDimensions.d.ts.map +1 -0
  295. package/dist/features/tabletop/utils/getTabletopCardDimensions.js +35 -0
  296. package/dist/features/tabletop/utils/getTabletopCardDimensions.js.map +1 -0
  297. package/dist/features/tabletop/utils/getTabletopSeatPosition.d.ts +9 -0
  298. package/dist/features/tabletop/utils/getTabletopSeatPosition.d.ts.map +1 -0
  299. package/dist/features/tabletop/utils/getTabletopSeatPosition.js +88 -0
  300. package/dist/features/tabletop/utils/getTabletopSeatPosition.js.map +1 -0
  301. package/dist/features/tree-view/adapters/inbound/TreeView.d.ts +1 -1
  302. package/dist/features/tree-view/adapters/inbound/TreeView.js +1 -1
  303. package/dist/features/tree-view/adapters/inbound/TreeView.js.map +1 -1
  304. package/dist/features/tree-view/adapters/inbound/web-artifact/TreeView.d.ts +1 -1
  305. package/dist/features/tree-view/adapters/inbound/web-artifact/TreeView.js +1 -1
  306. package/dist/features/tree-view/adapters/inbound/web-artifact/TreeView.js.map +1 -1
  307. package/dist/features/typography/adapters/inbound/Heading.d.ts +0 -4
  308. package/dist/features/typography/adapters/inbound/Heading.d.ts.map +1 -1
  309. package/dist/features/typography/adapters/inbound/Heading.js +0 -4
  310. package/dist/features/typography/adapters/inbound/Heading.js.map +1 -1
  311. package/dist/features/typography/adapters/inbound/Text.d.ts +0 -4
  312. package/dist/features/typography/adapters/inbound/Text.d.ts.map +1 -1
  313. package/dist/features/typography/adapters/inbound/Text.js +0 -4
  314. package/dist/features/typography/adapters/inbound/Text.js.map +1 -1
  315. package/dist/index.d.ts +8 -0
  316. package/dist/index.d.ts.map +1 -1
  317. package/dist/index.js +4 -0
  318. package/dist/index.js.map +1 -1
  319. package/dist/types/chess.d.ts +83 -0
  320. package/dist/types/chess.d.ts.map +1 -0
  321. package/dist/types/chess.js +2 -0
  322. package/dist/types/chess.js.map +1 -0
  323. package/dist/types/gamePresentation.d.ts +94 -0
  324. package/dist/types/gamePresentation.d.ts.map +1 -0
  325. package/dist/types/gamePresentation.js +2 -0
  326. package/dist/types/gamePresentation.js.map +1 -0
  327. package/dist/types/gameRuntime.d.ts +29 -0
  328. package/dist/types/gameRuntime.d.ts.map +1 -0
  329. package/dist/types/gameRuntime.js +2 -0
  330. package/dist/types/gameRuntime.js.map +1 -0
  331. package/dist/types/tabletop.d.ts +129 -0
  332. package/dist/types/tabletop.d.ts.map +1 -0
  333. package/dist/types/tabletop.js +2 -0
  334. package/dist/types/tabletop.js.map +1 -0
  335. package/package.json +6 -7
  336. package/src/features/authoring/allowedChildren.ts +15 -2
  337. package/src/features/authoring/componentMeta.test.ts +93 -0
  338. package/src/features/authoring/componentMeta.ts +27 -0
  339. package/src/features/authoring/constants.ts +3 -0
  340. package/src/features/button/adapters/inbound/Button.tsx +0 -4
  341. package/src/features/card/adapters/inbound/Card.tsx +0 -4
  342. package/src/features/card/cardMeta.ts +12 -2
  343. package/src/features/chess/adapters/inbound/ChessBoard.tsx +169 -0
  344. package/src/features/chess/adapters/inbound/OpeningBook.tsx +131 -0
  345. package/src/features/chess/meta.ts +168 -0
  346. package/src/features/chess/public.test.tsx +165 -0
  347. package/src/features/chess/public.ts +27 -0
  348. package/src/features/chess/utils/chessSquares.ts +6 -0
  349. package/src/features/chess/utils/createBoardSquares.ts +13 -0
  350. package/src/features/chess/utils/createChessBoardColorScheme.ts +55 -0
  351. package/src/features/chess/utils/createOpeningBookColorScheme.ts +26 -0
  352. package/src/features/chess/utils/getSquareFile.ts +6 -0
  353. package/src/features/chess/utils/getSquareRank.ts +6 -0
  354. package/src/features/chess/utils/isLightSquare.ts +8 -0
  355. package/src/features/chessTabletopOwnership.test.ts +71 -0
  356. package/src/features/empty-state/adapters/inbound/EmptyState.tsx +0 -4
  357. package/src/features/form/text-input/adapters/inbound/TextInput.tsx +0 -4
  358. package/src/features/game/adapters/inbound/Game.tsx +43 -0
  359. package/src/features/game/adapters/inbound/GameEntity.tsx +44 -0
  360. package/src/features/game/adapters/inbound/GameField.tsx +52 -0
  361. package/src/features/game/adapters/inbound/GameInputZone.tsx +99 -0
  362. package/src/features/game/adapters/inbound/GameMeasurementProbe.tsx +83 -0
  363. package/src/features/game/adapters/inbound/GameOverlay.tsx +58 -0
  364. package/src/features/game/adapters/inbound/createGameKeyboardEvent.test.ts +51 -0
  365. package/src/features/game/adapters/inbound/createGameKeyboardEvent.ts +33 -0
  366. package/src/features/game/adapters/inbound/createGameMeasurementEvent.test.ts +56 -0
  367. package/src/features/game/adapters/inbound/createGameMeasurementEvent.ts +38 -0
  368. package/src/features/game/adapters/inbound/createGamePointerEvent.test.ts +56 -0
  369. package/src/features/game/adapters/inbound/createGamePointerEvent.ts +39 -0
  370. package/src/features/game/adapters/inbound/measureGameEntity.ts +28 -0
  371. package/src/features/game/adapters/inbound/useGameInputZoneResponder.ts +85 -0
  372. package/src/features/game/composition/GameRuntimeContext.ts +6 -0
  373. package/src/features/game/composition/createGameBindingContext.test.ts +66 -0
  374. package/src/features/game/composition/createGameBindingContext.ts +11 -0
  375. package/src/features/game/composition/createGameMeasurementRegistry.test.ts +35 -0
  376. package/src/features/game/composition/createGameMeasurementRegistry.ts +16 -0
  377. package/src/features/game/composition/useGameRuntime.test.tsx +173 -0
  378. package/src/features/game/composition/useGameRuntime.ts +200 -0
  379. package/src/features/game/composition/useGameScheduledEffects.ts +85 -0
  380. package/src/features/game/meta/gameEntityMeta.ts +226 -0
  381. package/src/features/game/meta/gameFieldMeta.ts +49 -0
  382. package/src/features/game/meta/gameInputZoneMeta.ts +140 -0
  383. package/src/features/game/meta/gameMeasurementProbeMeta.ts +72 -0
  384. package/src/features/game/meta/gameMeta.ts +115 -0
  385. package/src/features/game/meta/gameOverlayMeta.ts +66 -0
  386. package/src/features/game/public.test.tsx +64 -0
  387. package/src/features/game/public.ts +19 -0
  388. package/src/features/game/utils/clampGamePercentage.ts +4 -0
  389. package/src/features/game/utils/resolveGameEntityMotionPlan.test.ts +63 -0
  390. package/src/features/game/utils/resolveGameEntityMotionPlan.ts +53 -0
  391. package/src/features/game/utils/toGamePercentage.ts +6 -0
  392. package/src/features/game/utils/useAnimatedGameEntityValue.ts +41 -0
  393. package/src/features/game/utils/useGameEntityAnimatedStyle.ts +87 -0
  394. package/src/features/game/utils/useGameEntityMeasurement.ts +19 -0
  395. package/src/features/game/utils/useGameEntityMotionProgress.ts +114 -0
  396. package/src/features/game/utils/useGameReducedMotion.ts +15 -0
  397. package/src/features/graph-view/adapters/inbound/web-artifact/GraphView.tsx +5 -5
  398. package/src/features/graph-view/adapters/inbound/web-artifact/compactGraphSpacing.ts +1 -1
  399. package/src/features/graph-view/adapters/inbound/web-artifact/createGraphController.ts +1 -1
  400. package/src/features/graph-view/adapters/inbound/web-artifact/createGraphLoopSizer.ts +1 -1
  401. package/src/features/graph-view/adapters/inbound/web-artifact/createGraphRuntime.ts +7 -7
  402. package/src/features/graph-view/adapters/inbound/web-artifact/getGraphGeometryKey.ts +0 -1
  403. package/src/features/graph-view/adapters/inbound/web-artifact/getGraphTopologyKey.ts +1 -1
  404. package/src/features/graph-view/adapters/inbound/web-artifact/hasGraphLayoutChanged.ts +0 -1
  405. package/src/features/graph-view/adapters/inbound/web-artifact/runDetachedGraphLayout.ts +1 -1
  406. package/src/features/graph-view/adapters/inbound/web-artifact/sizeGraphNodesToLabels.ts +1 -1
  407. package/src/features/graph-view/adapters/inbound/web-artifact/syncGraphElements.ts +0 -1
  408. package/src/features/layout/gridMeta.ts +12 -2
  409. package/src/features/layout/viewMeta.ts +10 -2
  410. package/src/features/registry/ZORA_COMPONENT_REGISTRY.ts +29 -0
  411. package/src/features/tabletop/adapters/inbound/CardBack.tsx +70 -0
  412. package/src/features/tabletop/adapters/inbound/CardHand.tsx +61 -0
  413. package/src/features/tabletop/adapters/inbound/PlayingCard.tsx +95 -0
  414. package/src/features/tabletop/adapters/inbound/PokerTrainingTable.tsx +34 -0
  415. package/src/features/tabletop/adapters/inbound/TabletopTable.tsx +264 -0
  416. package/src/features/tabletop/meta.ts +254 -0
  417. package/src/features/tabletop/public.test.tsx +127 -0
  418. package/src/features/tabletop/public.ts +32 -0
  419. package/src/features/tabletop/utils/createPokerTrainingTableState.ts +152 -0
  420. package/src/features/tabletop/utils/createTabletopColorScheme.ts +232 -0
  421. package/src/features/tabletop/utils/createTabletopGameSeats.ts +31 -0
  422. package/src/features/tabletop/utils/getPlayingCardLabel.ts +8 -0
  423. package/src/features/tabletop/utils/getTabletopCardDimensions.ts +45 -0
  424. package/src/features/tabletop/utils/getTabletopSeatPosition.ts +100 -0
  425. package/src/features/tree-view/adapters/inbound/TreeView.tsx +1 -1
  426. package/src/features/tree-view/adapters/inbound/web-artifact/TreeView.tsx +1 -1
  427. package/src/features/typography/adapters/inbound/Heading.tsx +0 -4
  428. package/src/features/typography/adapters/inbound/Text.tsx +0 -4
  429. package/src/index.ts +83 -0
  430. package/src/types/chess.ts +95 -0
  431. package/src/types/gamePresentation.ts +103 -0
  432. package/src/types/gameRuntime.ts +34 -0
  433. package/src/types/tabletop.ts +131 -0
  434. package/web-dist/chunks/{Accordion-cscmtcn8.js → Accordion-0txegc16.js} +1 -1
  435. package/web-dist/chunks/{Accordion-06588rzn.js → Accordion-10xw59gm.js} +1 -1
  436. package/web-dist/chunks/{Accordion-8kgtg62g.js → Accordion-2zh15wt9.js} +6 -6
  437. package/web-dist/chunks/{Accordion-pkqj4g3r.js → Accordion-481bknsd.js} +5 -5
  438. package/web-dist/chunks/{Accordion-grfbz6f2.js → Accordion-4fkjn6r5.js} +1 -1
  439. package/web-dist/chunks/{Accordion-ftjkdjqs.js → Accordion-4gx45mn0.js} +3 -3
  440. package/web-dist/chunks/{Accordion-fjnck2tg.js → Accordion-4s69xvqy.js} +6 -6
  441. package/web-dist/chunks/{Accordion-jh7nxehr.js → Accordion-50jz5nhg.js} +1 -1
  442. package/web-dist/chunks/{Accordion-t6sdgmbz.js → Accordion-52xke54s.js} +1 -1
  443. package/web-dist/chunks/{Accordion-far6szrp.js → Accordion-6npzmbgk.js} +5 -5
  444. package/web-dist/chunks/{Accordion-q7c1ryf2.js → Accordion-6z4npcgf.js} +4 -4
  445. package/web-dist/chunks/{Accordion-gbba10rg.js → Accordion-8gw5tkfw.js} +6 -6
  446. package/web-dist/chunks/{Accordion-fmxygyb6.js → Accordion-8qteyww0.js} +4 -4
  447. package/web-dist/chunks/{Accordion-1pp37dtg.js → Accordion-9h5dx3ck.js} +4 -4
  448. package/web-dist/chunks/{Accordion-paha5aje.js → Accordion-9mmqf3wr.js} +2 -2
  449. package/web-dist/chunks/{Accordion-f5swy5bs.js → Accordion-b21zrnzj.js} +1 -1
  450. package/web-dist/chunks/{Accordion-ars389m1.js → Accordion-b8qd23hr.js} +3 -3
  451. package/web-dist/chunks/{Accordion-hxfa71g9.js → Accordion-c79y8g44.js} +7 -7
  452. package/web-dist/chunks/Accordion-ca2csh5r.js +321 -0
  453. package/web-dist/chunks/{Accordion-49gf1zb8.js → Accordion-cjht9dyv.js} +1 -1
  454. package/web-dist/chunks/{Accordion-sz21xsf4.js → Accordion-cq6hn45r.js} +1 -1
  455. package/web-dist/chunks/{Accordion-33rd76r7.js → Accordion-d90g9wcb.js} +8 -8
  456. package/web-dist/chunks/{Accordion-crx58d5n.js → Accordion-f5jb299b.js} +2 -2
  457. package/web-dist/chunks/{Accordion-h95wvyn5.js → Accordion-fe6vmbpf.js} +2 -2
  458. package/web-dist/chunks/{Accordion-jzbq36ec.js → Accordion-fqm027n3.js} +8 -8
  459. package/web-dist/chunks/{Accordion-0jkm3y3w.js → Accordion-gpccarct.js} +1 -1
  460. package/web-dist/chunks/{Accordion-v6ykq9hv.js → Accordion-h95h3xdb.js} +10 -10
  461. package/web-dist/chunks/{Accordion-t3p4ykg7.js → Accordion-j8ab9k8k.js} +8 -8
  462. package/web-dist/chunks/{Accordion-qpwhmqzd.js → Accordion-k5z591wx.js} +13 -13
  463. package/web-dist/chunks/{Accordion-rrpej6sv.js → Accordion-kdncjvc7.js} +7 -7
  464. package/web-dist/chunks/{Accordion-f05a7r28.js → Accordion-ks4a1c6w.js} +5 -5
  465. package/web-dist/chunks/{Accordion-x0j8b2by.js → Accordion-ma1sfe5z.js} +5 -5
  466. package/web-dist/chunks/{Accordion-2dws3778.js → Accordion-mhtyce1k.js} +4 -4
  467. package/web-dist/chunks/{Accordion-1vewf8aa.js → Accordion-n7gtb5ec.js} +2 -2
  468. package/web-dist/chunks/{Accordion-0psdn97s.js → Accordion-p42mm8rr.js} +1 -1
  469. package/web-dist/chunks/{Accordion-3404tth9.js → Accordion-panw5f0q.js} +7 -7
  470. package/web-dist/chunks/{Accordion-4a6wj3ez.js → Accordion-pxq8gfgg.js} +9 -9
  471. package/web-dist/chunks/{Accordion-xshn7k8f.js → Accordion-qwbshc4s.js} +4 -4
  472. package/web-dist/chunks/{Accordion-395r3wra.js → Accordion-r51wsmvy.js} +2 -2
  473. package/web-dist/chunks/Accordion-rt13cqr7.js +830 -0
  474. package/web-dist/chunks/{Accordion-hz4xaqjf.js → Accordion-s1f9hb5a.js} +9 -9
  475. package/web-dist/chunks/{Accordion-7ja4mtbz.js → Accordion-sv87mbqa.js} +1 -1
  476. package/web-dist/chunks/{Accordion-r4c9k9y7.js → Accordion-t4k9egq6.js} +2 -2
  477. package/web-dist/chunks/{Accordion-96cqeekv.js → Accordion-t64m1kca.js} +5 -5
  478. package/web-dist/chunks/Accordion-wg31jkvp.js +1559 -0
  479. package/web-dist/chunks/{Accordion-ch67q4t0.js → Accordion-y9zr4x2x.js} +4 -4
  480. package/web-dist/chunks/{Accordion-31aeqxak.js → Accordion-ye3k55r7.js} +3 -3
  481. package/web-dist/chunks/{Accordion-s42wwh6m.js → Accordion-z29agann.js} +6 -6
  482. package/web-dist/chunks/{Accordion-f1h2f05v.js → Accordion-ze26effy.js} +5 -5
  483. package/web-dist/chunks/{Accordion-tx78txec.js → Accordion-zqzcagxz.js} +5 -5
  484. package/web-dist/components/accordion/Accordion.js +12 -12
  485. package/web-dist/components/accordion-item/AccordionItem.js +12 -12
  486. package/web-dist/components/activity-indicator/ActivityIndicator.js +3 -3
  487. package/web-dist/components/app-bar/AppBar.js +19 -19
  488. package/web-dist/components/app-shell/AppShell.js +6 -6
  489. package/web-dist/components/avatar/Avatar.js +12 -12
  490. package/web-dist/components/avatar-group/AvatarGroup.js +12 -12
  491. package/web-dist/components/badge/Badge.js +7 -7
  492. package/web-dist/components/barcode-scanner-view/BarcodeScannerView.js +20 -20
  493. package/web-dist/components/bottom-sheet/BottomSheet.js +8 -8
  494. package/web-dist/components/bottom-sheet-flat-list/BottomSheetFlatList.js +8 -8
  495. package/web-dist/components/bottom-sheet-scroll-view/BottomSheetScrollView.js +8 -8
  496. package/web-dist/components/bottom-sheet-section-list/BottomSheetSectionList.js +8 -8
  497. package/web-dist/components/bottom-sheet-view/BottomSheetView.js +8 -8
  498. package/web-dist/components/bottom-sheet-virtualized-list/BottomSheetVirtualizedList.js +8 -8
  499. package/web-dist/components/breadcrumbs/Breadcrumbs.js +15 -15
  500. package/web-dist/components/button/Button.js +12 -12
  501. package/web-dist/components/button-group/ButtonGroup.js +12 -12
  502. package/web-dist/components/camera-permission-view/CameraPermissionView.js +20 -20
  503. package/web-dist/components/card/Card.js +19 -19
  504. package/web-dist/components/card-back/CardBack.d.ts +7 -0
  505. package/web-dist/components/card-back/CardBack.js +19 -0
  506. package/web-dist/components/card-back/index.d.ts +1 -0
  507. package/web-dist/components/card-back/index.js +2 -0
  508. package/web-dist/components/card-hand/CardHand.d.ts +7 -0
  509. package/web-dist/components/card-hand/CardHand.js +19 -0
  510. package/web-dist/components/card-hand/index.d.ts +1 -0
  511. package/web-dist/components/card-hand/index.js +2 -0
  512. package/web-dist/components/chat-list-item/ChatListItem.js +16 -16
  513. package/web-dist/components/checkbox/Checkbox.js +12 -12
  514. package/web-dist/components/checkbox-group/CheckboxGroup.js +12 -12
  515. package/web-dist/components/chess-board/ChessBoard.d.ts +4 -0
  516. package/web-dist/components/chess-board/ChessBoard.js +13 -0
  517. package/web-dist/components/chess-board/index.d.ts +1 -0
  518. package/web-dist/components/chess-board/index.js +2 -0
  519. package/web-dist/components/chip/Chip.js +13 -13
  520. package/web-dist/components/chip-group/ChipGroup.js +13 -13
  521. package/web-dist/components/collection-editor/CollectionEditor.js +19 -19
  522. package/web-dist/components/content-rail/ContentRail.js +13 -13
  523. package/web-dist/components/data-table/DataTable.js +26 -26
  524. package/web-dist/components/date-picker/DatePicker.js +17 -17
  525. package/web-dist/components/dialog/Dialog.js +12 -12
  526. package/web-dist/components/divider/Divider.js +6 -6
  527. package/web-dist/components/empty-state/EmptyState.js +20 -20
  528. package/web-dist/components/field/Field.js +12 -12
  529. package/web-dist/components/flat-list/FlatList.js +13 -13
  530. package/web-dist/components/forgot-password-form/ForgotPasswordForm.js +18 -18
  531. package/web-dist/components/form/Form.js +16 -16
  532. package/web-dist/components/form-actions/FormActions.js +16 -16
  533. package/web-dist/components/form-error/FormError.js +16 -16
  534. package/web-dist/components/game/Game.d.ts +8 -0
  535. package/web-dist/components/game/Game.js +25 -0
  536. package/web-dist/components/game/index.d.ts +1 -0
  537. package/web-dist/components/game/index.js +2 -0
  538. package/web-dist/components/game-entity/GameEntity.d.ts +8 -0
  539. package/web-dist/components/game-entity/GameEntity.js +25 -0
  540. package/web-dist/components/game-entity/index.d.ts +1 -0
  541. package/web-dist/components/game-entity/index.js +2 -0
  542. package/web-dist/components/game-field/GameField.d.ts +8 -0
  543. package/web-dist/components/game-field/GameField.js +25 -0
  544. package/web-dist/components/game-field/index.d.ts +1 -0
  545. package/web-dist/components/game-field/index.js +2 -0
  546. package/web-dist/components/game-input-zone/GameInputZone.d.ts +8 -0
  547. package/web-dist/components/game-input-zone/GameInputZone.js +25 -0
  548. package/web-dist/components/game-input-zone/index.d.ts +1 -0
  549. package/web-dist/components/game-input-zone/index.js +2 -0
  550. package/web-dist/components/game-measurement-probe/GameMeasurementProbe.d.ts +8 -0
  551. package/web-dist/components/game-measurement-probe/GameMeasurementProbe.js +25 -0
  552. package/web-dist/components/game-measurement-probe/index.d.ts +1 -0
  553. package/web-dist/components/game-measurement-probe/index.js +2 -0
  554. package/web-dist/components/game-overlay/GameOverlay.d.ts +8 -0
  555. package/web-dist/components/game-overlay/GameOverlay.js +25 -0
  556. package/web-dist/components/game-overlay/index.d.ts +1 -0
  557. package/web-dist/components/game-overlay/index.js +2 -0
  558. package/web-dist/components/gradient/Gradient.js +7 -7
  559. package/web-dist/components/gradient-renderer-provider/GradientRendererProvider.js +7 -7
  560. package/web-dist/components/graph-view/GraphView.d.ts +5 -5
  561. package/web-dist/components/grid/Grid.js +6 -6
  562. package/web-dist/components/heading/Heading.js +6 -6
  563. package/web-dist/components/hero/Hero.js +19 -19
  564. package/web-dist/components/icon/Icon.js +4 -4
  565. package/web-dist/components/icon-button/IconButton.js +12 -12
  566. package/web-dist/components/image/Image.js +10 -10
  567. package/web-dist/components/keyboard-avoiding-view/KeyboardAvoidingView.js +2 -2
  568. package/web-dist/components/list/List.js +13 -13
  569. package/web-dist/components/list-item/ListItem.js +13 -13
  570. package/web-dist/components/list-section/ListSection.js +13 -13
  571. package/web-dist/components/media-card/MediaCard.js +19 -19
  572. package/web-dist/components/message-bubble/MessageBubble.js +16 -16
  573. package/web-dist/components/metric-card/MetricCard.js +19 -19
  574. package/web-dist/components/missing-element/MissingElement.js +11 -11
  575. package/web-dist/components/o-auth-provider-button/OAuthProviderButton.js +18 -18
  576. package/web-dist/components/o-auth-provider-list/OAuthProviderList.js +18 -18
  577. package/web-dist/components/opening-book/OpeningBook.d.ts +4 -0
  578. package/web-dist/components/opening-book/OpeningBook.js +13 -0
  579. package/web-dist/components/opening-book/index.d.ts +1 -0
  580. package/web-dist/components/opening-book/index.js +2 -0
  581. package/web-dist/components/otp-form/OtpForm.js +18 -18
  582. package/web-dist/components/pagination/Pagination.js +13 -13
  583. package/web-dist/components/palette-item/PaletteItem.js +19 -19
  584. package/web-dist/components/playing-card/PlayingCard.d.ts +7 -0
  585. package/web-dist/components/playing-card/PlayingCard.js +19 -0
  586. package/web-dist/components/playing-card/index.d.ts +1 -0
  587. package/web-dist/components/playing-card/index.js +2 -0
  588. package/web-dist/components/poker-training-table/PokerTrainingTable.d.ts +7 -0
  589. package/web-dist/components/poker-training-table/PokerTrainingTable.js +19 -0
  590. package/web-dist/components/poker-training-table/index.d.ts +1 -0
  591. package/web-dist/components/poker-training-table/index.js +2 -0
  592. package/web-dist/components/popover-menu/PopoverMenu.js +14 -14
  593. package/web-dist/components/post-card/PostCard.js +19 -19
  594. package/web-dist/components/product-card/ProductCard.js +19 -19
  595. package/web-dist/components/progress/Progress.js +10 -10
  596. package/web-dist/components/progress-ring/ProgressRing.js +10 -10
  597. package/web-dist/components/radio/Radio.js +14 -14
  598. package/web-dist/components/radio-group/RadioGroup.js +14 -14
  599. package/web-dist/components/rating/Rating.js +9 -9
  600. package/web-dist/components/reader-surface/ReaderSurface.js +21 -21
  601. package/web-dist/components/scan-overlay/ScanOverlay.js +20 -20
  602. package/web-dist/components/screen/Screen.js +6 -6
  603. package/web-dist/components/screen-section/ScreenSection.js +10 -10
  604. package/web-dist/components/scroll-view/ScrollView.js +6 -6
  605. package/web-dist/components/search-input/SearchInput.js +13 -13
  606. package/web-dist/components/section-header/SectionHeader.js +10 -10
  607. package/web-dist/components/section-list/SectionList.js +13 -13
  608. package/web-dist/components/select/Select.js +16 -16
  609. package/web-dist/components/selectable-item/SelectableItem.js +5 -5
  610. package/web-dist/components/selection-provider/SelectionProvider.js +5 -5
  611. package/web-dist/components/sign-in-form/SignInForm.js +18 -18
  612. package/web-dist/components/sign-up-form/SignUpForm.js +18 -18
  613. package/web-dist/components/skeleton/Skeleton.js +22 -22
  614. package/web-dist/components/skeleton-card/SkeletonCard.js +22 -22
  615. package/web-dist/components/skeleton-list/SkeletonList.js +22 -22
  616. package/web-dist/components/skeleton-text/SkeletonText.js +22 -22
  617. package/web-dist/components/surface/Surface.js +7 -7
  618. package/web-dist/components/switch/Switch.js +7 -7
  619. package/web-dist/components/tab/Tab.js +7 -7
  620. package/web-dist/components/tab-list/TabList.js +7 -7
  621. package/web-dist/components/tab-panel/TabPanel.js +7 -7
  622. package/web-dist/components/tabletop-table/TabletopTable.d.ts +7 -0
  623. package/web-dist/components/tabletop-table/TabletopTable.js +19 -0
  624. package/web-dist/components/tabletop-table/index.d.ts +1 -0
  625. package/web-dist/components/tabletop-table/index.js +2 -0
  626. package/web-dist/components/tabs/Tabs.js +7 -7
  627. package/web-dist/components/text/Text.js +6 -6
  628. package/web-dist/components/text-input/TextInput.js +13 -13
  629. package/web-dist/components/time-picker/TimePicker.js +17 -17
  630. package/web-dist/components/timeline/Timeline.js +11 -11
  631. package/web-dist/components/toast/Toast.js +9 -9
  632. package/web-dist/components/toast-provider/ToastProvider.js +9 -9
  633. package/web-dist/components/toolbar/Toolbar.js +19 -19
  634. package/web-dist/components/tree-item/TreeItem.js +16 -16
  635. package/web-dist/components/tree-view/TreeView.d.ts +1 -1
  636. package/web-dist/components/uploader/Uploader.js +22 -22
  637. package/web-dist/components/view/View.js +6 -6
  638. package/web-dist/manifest.json +1650 -1379
  639. package/web-dist/runtime/ZoraProvider.js +8 -8
@@ -0,0 +1,52 @@
1
+ import { Animated } from 'react-native';
2
+ import { resolveGameEntityMotionPlan } from './resolveGameEntityMotionPlan';
3
+ import { useAnimatedGameEntityValue } from './useAnimatedGameEntityValue';
4
+ import { useGameEntityMotionProgress } from './useGameEntityMotionProgress';
5
+ import { useGameReducedMotion } from './useGameReducedMotion';
6
+ /*** Compose bound GameEntity values with optional relative presentation motion. */
7
+ export function useGameEntityAnimatedStyle(input) {
8
+ const reduceMotion = useGameReducedMotion();
9
+ const plan = resolveGameEntityMotionPlan(input, reduceMotion);
10
+ const values = {
11
+ x: useAnimatedGameEntityValue(input.x ?? 0, plan.transitionDurationMs, plan.transitionEasing),
12
+ y: useAnimatedGameEntityValue(input.y ?? 0, plan.transitionDurationMs, plan.transitionEasing),
13
+ opacity: useAnimatedGameEntityValue(input.opacity ?? 1, plan.transitionDurationMs, plan.transitionEasing),
14
+ scale: useAnimatedGameEntityValue(input.scale ?? 1, plan.transitionDurationMs, plan.transitionEasing),
15
+ rotation: useAnimatedGameEntityValue(input.rotation ?? 0, plan.transitionDurationMs, plan.transitionEasing),
16
+ progress: useGameEntityMotionProgress(plan),
17
+ };
18
+ return createGameEntityAnimatedStyle(values, input);
19
+ }
20
+ /*** Build one animated React Native style from base values and relative motion progress. */
21
+ function createGameEntityAnimatedStyle(values, input) {
22
+ const left = Animated.add(values.x, Animated.multiply(values.progress, input.motionOffsetX ?? 0));
23
+ const top = Animated.add(values.y, Animated.multiply(values.progress, input.motionOffsetY ?? 0));
24
+ const opacity = Animated.add(values.opacity, Animated.multiply(values.progress, input.motionOpacityDelta ?? 0));
25
+ const scale = Animated.add(values.scale, Animated.multiply(values.progress, input.motionScaleDelta ?? 0));
26
+ const rotation = Animated.add(values.rotation, Animated.multiply(values.progress, input.motionRotationDelta ?? 0));
27
+ return {
28
+ left: left.interpolate({
29
+ inputRange: [-10_000, 10_000],
30
+ outputRange: ['-10000%', '10000%'],
31
+ }),
32
+ top: top.interpolate({
33
+ inputRange: [-10_000, 10_000],
34
+ outputRange: ['-10000%', '10000%'],
35
+ }),
36
+ opacity: opacity.interpolate({
37
+ inputRange: [0, 1],
38
+ outputRange: [0, 1],
39
+ extrapolate: 'clamp',
40
+ }),
41
+ transform: [
42
+ { scale },
43
+ {
44
+ rotate: rotation.interpolate({
45
+ inputRange: [-36_000, 36_000],
46
+ outputRange: ['-36000deg', '36000deg'],
47
+ }),
48
+ },
49
+ ],
50
+ };
51
+ }
52
+ //# sourceMappingURL=useGameEntityAnimatedStyle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useGameEntityAnimatedStyle.js","sourceRoot":"","sources":["../../../../src/features/game/utils/useGameEntityAnimatedStyle.ts"],"names":[],"mappings":"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","sourcesContent":["import { Animated } from 'react-native';\n\nimport type { GameEntityProps } from '../../../types/gamePresentation';\nimport { resolveGameEntityMotionPlan } from './resolveGameEntityMotionPlan';\nimport { useAnimatedGameEntityValue } from './useAnimatedGameEntityValue';\nimport { useGameEntityMotionProgress } from './useGameEntityMotionProgress';\nimport { useGameReducedMotion } from './useGameReducedMotion';\n\ninterface GameEntityAnimatedValues {\n readonly x: Animated.Value;\n readonly y: Animated.Value;\n readonly opacity: Animated.Value;\n readonly scale: Animated.Value;\n readonly rotation: Animated.Value;\n readonly progress: Animated.Value;\n}\n\n/*** Compose bound GameEntity values with optional relative presentation motion. */\nexport function useGameEntityAnimatedStyle(input: GameEntityProps) {\n const reduceMotion = useGameReducedMotion();\n const plan = resolveGameEntityMotionPlan(input, reduceMotion);\n const values: GameEntityAnimatedValues = {\n x: useAnimatedGameEntityValue(input.x ?? 0, plan.transitionDurationMs, plan.transitionEasing),\n y: useAnimatedGameEntityValue(input.y ?? 0, plan.transitionDurationMs, plan.transitionEasing),\n opacity: useAnimatedGameEntityValue(\n input.opacity ?? 1,\n plan.transitionDurationMs,\n plan.transitionEasing,\n ),\n scale: useAnimatedGameEntityValue(\n input.scale ?? 1,\n plan.transitionDurationMs,\n plan.transitionEasing,\n ),\n rotation: useAnimatedGameEntityValue(\n input.rotation ?? 0,\n plan.transitionDurationMs,\n plan.transitionEasing,\n ),\n progress: useGameEntityMotionProgress(plan),\n };\n\n return createGameEntityAnimatedStyle(values, input);\n}\n\n/*** Build one animated React Native style from base values and relative motion progress. */\nfunction createGameEntityAnimatedStyle(values: GameEntityAnimatedValues, input: GameEntityProps) {\n const left = Animated.add(values.x, Animated.multiply(values.progress, input.motionOffsetX ?? 0));\n const top = Animated.add(values.y, Animated.multiply(values.progress, input.motionOffsetY ?? 0));\n const opacity = Animated.add(\n values.opacity,\n Animated.multiply(values.progress, input.motionOpacityDelta ?? 0),\n );\n const scale = Animated.add(\n values.scale,\n Animated.multiply(values.progress, input.motionScaleDelta ?? 0),\n );\n const rotation = Animated.add(\n values.rotation,\n Animated.multiply(values.progress, input.motionRotationDelta ?? 0),\n );\n\n return {\n left: left.interpolate({\n inputRange: [-10_000, 10_000],\n outputRange: ['-10000%', '10000%'],\n }),\n top: top.interpolate({\n inputRange: [-10_000, 10_000],\n outputRange: ['-10000%', '10000%'],\n }),\n opacity: opacity.interpolate({\n inputRange: [0, 1],\n outputRange: [0, 1],\n extrapolate: 'clamp',\n }),\n transform: [\n { scale },\n {\n rotate: rotation.interpolate({\n inputRange: [-36_000, 36_000],\n outputRange: ['-36000deg', '36000deg'],\n }),\n },\n ],\n };\n}\n"]}
@@ -0,0 +1,5 @@
1
+ import React from 'react';
2
+ import type { View } from 'react-native';
3
+ /*** Register one optional measurable GameEntity view inside its local Game scope. */
4
+ export declare function useGameEntityMeasurement(elementRef: React.RefObject<View | null>, measurementId: string | undefined): void;
5
+ //# sourceMappingURL=useGameEntityMeasurement.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useGameEntityMeasurement.d.ts","sourceRoot":"","sources":["../../../../src/features/game/utils/useGameEntityMeasurement.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAKzC,qFAAqF;AACrF,wBAAgB,wBAAwB,CACtC,UAAU,EAAE,KAAK,CAAC,SAAS,CAAC,IAAI,GAAG,IAAI,CAAC,EACxC,aAAa,EAAE,MAAM,GAAG,SAAS,GAChC,IAAI,CAQN"}
@@ -0,0 +1,14 @@
1
+ import React from 'react';
2
+ import { measureGameEntity } from '../adapters/inbound/measureGameEntity';
3
+ import { GameRuntimeContext } from '../composition/GameRuntimeContext';
4
+ /*** Register one optional measurable GameEntity view inside its local Game scope. */
5
+ export function useGameEntityMeasurement(elementRef, measurementId) {
6
+ const runtime = React.useContext(GameRuntimeContext);
7
+ const registerMeasurement = runtime?.registerMeasurement;
8
+ React.useEffect(() => {
9
+ if (measurementId === undefined || registerMeasurement === undefined)
10
+ return undefined;
11
+ return registerMeasurement(measurementId, () => measureGameEntity(elementRef.current));
12
+ }, [elementRef, measurementId, registerMeasurement]);
13
+ }
14
+ //# sourceMappingURL=useGameEntityMeasurement.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useGameEntityMeasurement.js","sourceRoot":"","sources":["../../../../src/features/game/utils/useGameEntityMeasurement.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,OAAO,EAAE,iBAAiB,EAAE,MAAM,uCAAuC,CAAC;AAC1E,OAAO,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AAEvE,qFAAqF;AACrF,MAAM,UAAU,wBAAwB,CACtC,UAAwC,EACxC,aAAiC;IAEjC,MAAM,OAAO,GAAG,KAAK,CAAC,UAAU,CAAC,kBAAkB,CAAC,CAAC;IACrD,MAAM,mBAAmB,GAAG,OAAO,EAAE,mBAAmB,CAAC;IAEzD,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE;QACnB,IAAI,aAAa,KAAK,SAAS,IAAI,mBAAmB,KAAK,SAAS;YAAE,OAAO,SAAS,CAAC;QACvF,OAAO,mBAAmB,CAAC,aAAa,EAAE,GAAG,EAAE,CAAC,iBAAiB,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC;IACzF,CAAC,EAAE,CAAC,UAAU,EAAE,aAAa,EAAE,mBAAmB,CAAC,CAAC,CAAC;AACvD,CAAC","sourcesContent":["import React from 'react';\nimport type { View } from 'react-native';\n\nimport { measureGameEntity } from '../adapters/inbound/measureGameEntity';\nimport { GameRuntimeContext } from '../composition/GameRuntimeContext';\n\n/*** Register one optional measurable GameEntity view inside its local Game scope. */\nexport function useGameEntityMeasurement(\n elementRef: React.RefObject<View | null>,\n measurementId: string | undefined,\n): void {\n const runtime = React.useContext(GameRuntimeContext);\n const registerMeasurement = runtime?.registerMeasurement;\n\n React.useEffect(() => {\n if (measurementId === undefined || registerMeasurement === undefined) return undefined;\n return registerMeasurement(measurementId, () => measureGameEntity(elementRef.current));\n }, [elementRef, measurementId, registerMeasurement]);\n}\n"]}
@@ -0,0 +1,5 @@
1
+ import { Animated } from 'react-native';
2
+ import type { GameEntityMotionPlan } from './resolveGameEntityMotionPlan';
3
+ /*** Drive one optional relative GameEntity motion timeline without changing game-session state. */
4
+ export declare function useGameEntityMotionProgress(plan: GameEntityMotionPlan): Animated.Value;
5
+ //# sourceMappingURL=useGameEntityMotionProgress.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useGameEntityMotionProgress.d.ts","sourceRoot":"","sources":["../../../../src/features/game/utils/useGameEntityMotionProgress.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAU,MAAM,cAAc,CAAC;AAGhD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAU1E,mGAAmG;AACnG,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,oBAAoB,GAAG,QAAQ,CAAC,KAAK,CAmDtF"}
@@ -0,0 +1,87 @@
1
+ import React from 'react';
2
+ import { Animated, Easing } from 'react-native';
3
+ /*** Drive one optional relative GameEntity motion timeline without changing game-session state. */
4
+ export function useGameEntityMotionProgress(plan) {
5
+ const [progress] = React.useState(() => new Animated.Value(0));
6
+ const signature = createMotionSignature(plan);
7
+ const previousSignature = React.useRef(signature);
8
+ const { motionEnabled, motionPaused, motionDurationMs, motionDelayMs, motionEasing, motionRepeat, motionAlternate, } = plan;
9
+ React.useEffect(() => {
10
+ progress.stopAnimation();
11
+ if (!motionEnabled) {
12
+ progress.setValue(0);
13
+ return undefined;
14
+ }
15
+ if (previousSignature.current !== signature) {
16
+ progress.setValue(0);
17
+ previousSignature.current = signature;
18
+ }
19
+ if (motionPaused)
20
+ return undefined;
21
+ const animation = createMotionAnimation(progress, {
22
+ durationMs: motionDurationMs,
23
+ delayMs: motionDelayMs,
24
+ easing: motionEasing,
25
+ repeat: motionRepeat,
26
+ alternate: motionAlternate,
27
+ });
28
+ animation.start();
29
+ return () => animation.stop();
30
+ }, [
31
+ motionAlternate,
32
+ motionDelayMs,
33
+ motionDurationMs,
34
+ motionEasing,
35
+ motionEnabled,
36
+ motionPaused,
37
+ motionRepeat,
38
+ progress,
39
+ signature,
40
+ ]);
41
+ return progress;
42
+ }
43
+ /*** Create the one-shot or repeating React Native motion sequence for one entity. */
44
+ function createMotionAnimation(progress, input) {
45
+ const forward = () => Animated.timing(progress, {
46
+ toValue: 1,
47
+ duration: input.durationMs,
48
+ easing: resolveMotionEasing(input.easing),
49
+ useNativeDriver: false,
50
+ });
51
+ const reverse = () => Animated.timing(progress, {
52
+ toValue: 0,
53
+ duration: input.durationMs,
54
+ easing: resolveMotionEasing(input.easing),
55
+ useNativeDriver: false,
56
+ });
57
+ const movement = input.alternate
58
+ ? Animated.loop(Animated.sequence([forward(), reverse()]))
59
+ : input.repeat
60
+ ? Animated.loop(forward())
61
+ : forward();
62
+ return input.delayMs === 0
63
+ ? movement
64
+ : Animated.sequence([Animated.delay(input.delayMs), movement]);
65
+ }
66
+ /*** Create a stable signature for motion parameters that should restart the relative timeline. */
67
+ function createMotionSignature(plan) {
68
+ return [
69
+ plan.motionDurationMs,
70
+ plan.motionDelayMs,
71
+ plan.motionEasing,
72
+ plan.motionEnabled,
73
+ plan.motionRepeat,
74
+ plan.motionAlternate,
75
+ ].join(':');
76
+ }
77
+ /*** Map serializable timeline easing names onto React Native easing functions. */
78
+ function resolveMotionEasing(easing) {
79
+ if (easing === 'ease-in')
80
+ return Easing.in(Easing.ease);
81
+ if (easing === 'ease-out')
82
+ return Easing.out(Easing.ease);
83
+ if (easing === 'ease-in-out')
84
+ return Easing.inOut(Easing.ease);
85
+ return Easing.linear;
86
+ }
87
+ //# sourceMappingURL=useGameEntityMotionProgress.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useGameEntityMotionProgress.js","sourceRoot":"","sources":["../../../../src/features/game/utils/useGameEntityMotionProgress.ts"],"names":[],"mappings":"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","sourcesContent":["import React from 'react';\nimport { Animated, Easing } from 'react-native';\n\nimport type { GameEntityEasing } from '../../../types/gamePresentation';\nimport type { GameEntityMotionPlan } from './resolveGameEntityMotionPlan';\n\ninterface MotionAnimationInput {\n readonly durationMs: number;\n readonly delayMs: number;\n readonly easing: GameEntityEasing;\n readonly repeat: boolean;\n readonly alternate: boolean;\n}\n\n/*** Drive one optional relative GameEntity motion timeline without changing game-session state. */\nexport function useGameEntityMotionProgress(plan: GameEntityMotionPlan): Animated.Value {\n const [progress] = React.useState(() => new Animated.Value(0));\n const signature = createMotionSignature(plan);\n const previousSignature = React.useRef(signature);\n const {\n motionEnabled,\n motionPaused,\n motionDurationMs,\n motionDelayMs,\n motionEasing,\n motionRepeat,\n motionAlternate,\n } = plan;\n\n React.useEffect(() => {\n progress.stopAnimation();\n\n if (!motionEnabled) {\n progress.setValue(0);\n return undefined;\n }\n\n if (previousSignature.current !== signature) {\n progress.setValue(0);\n previousSignature.current = signature;\n }\n\n if (motionPaused) return undefined;\n\n const animation = createMotionAnimation(progress, {\n durationMs: motionDurationMs,\n delayMs: motionDelayMs,\n easing: motionEasing,\n repeat: motionRepeat,\n alternate: motionAlternate,\n });\n animation.start();\n return () => animation.stop();\n }, [\n motionAlternate,\n motionDelayMs,\n motionDurationMs,\n motionEasing,\n motionEnabled,\n motionPaused,\n motionRepeat,\n progress,\n signature,\n ]);\n\n return progress;\n}\n\n/*** Create the one-shot or repeating React Native motion sequence for one entity. */\nfunction createMotionAnimation(progress: Animated.Value, input: MotionAnimationInput) {\n const forward = () =>\n Animated.timing(progress, {\n toValue: 1,\n duration: input.durationMs,\n easing: resolveMotionEasing(input.easing),\n useNativeDriver: false,\n });\n const reverse = () =>\n Animated.timing(progress, {\n toValue: 0,\n duration: input.durationMs,\n easing: resolveMotionEasing(input.easing),\n useNativeDriver: false,\n });\n const movement = input.alternate\n ? Animated.loop(Animated.sequence([forward(), reverse()]))\n : input.repeat\n ? Animated.loop(forward())\n : forward();\n\n return input.delayMs === 0\n ? movement\n : Animated.sequence([Animated.delay(input.delayMs), movement]);\n}\n\n/*** Create a stable signature for motion parameters that should restart the relative timeline. */\nfunction createMotionSignature(plan: GameEntityMotionPlan): string {\n return [\n plan.motionDurationMs,\n plan.motionDelayMs,\n plan.motionEasing,\n plan.motionEnabled,\n plan.motionRepeat,\n plan.motionAlternate,\n ].join(':');\n}\n\n/*** Map serializable timeline easing names onto React Native easing functions. */\nfunction resolveMotionEasing(easing: GameEntityEasing) {\n if (easing === 'ease-in') return Easing.in(Easing.ease);\n if (easing === 'ease-out') return Easing.out(Easing.ease);\n if (easing === 'ease-in-out') return Easing.inOut(Easing.ease);\n return Easing.linear;\n}\n"]}
@@ -0,0 +1,3 @@
1
+ /*** Track the cross-platform system reduced-motion preference for game presentation. */
2
+ export declare function useGameReducedMotion(): boolean;
3
+ //# sourceMappingURL=useGameReducedMotion.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useGameReducedMotion.d.ts","sourceRoot":"","sources":["../../../../src/features/game/utils/useGameReducedMotion.ts"],"names":[],"mappings":"AAGA,wFAAwF;AACxF,wBAAgB,oBAAoB,IAAI,OAAO,CAU9C"}
@@ -0,0 +1,13 @@
1
+ import React from 'react';
2
+ import { AccessibilityInfo } from 'react-native';
3
+ /*** Track the cross-platform system reduced-motion preference for game presentation. */
4
+ export function useGameReducedMotion() {
5
+ const [reduceMotion, setReduceMotion] = React.useState(false);
6
+ React.useEffect(() => {
7
+ void AccessibilityInfo.isReduceMotionEnabled().then(setReduceMotion);
8
+ const subscription = AccessibilityInfo.addEventListener('reduceMotionChanged', setReduceMotion);
9
+ return () => subscription.remove();
10
+ }, []);
11
+ return reduceMotion;
12
+ }
13
+ //# sourceMappingURL=useGameReducedMotion.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useGameReducedMotion.js","sourceRoot":"","sources":["../../../../src/features/game/utils/useGameReducedMotion.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAEjD,wFAAwF;AACxF,MAAM,UAAU,oBAAoB;IAClC,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAE9D,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE;QACnB,KAAK,iBAAiB,CAAC,qBAAqB,EAAE,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QACrE,MAAM,YAAY,GAAG,iBAAiB,CAAC,gBAAgB,CAAC,qBAAqB,EAAE,eAAe,CAAC,CAAC;QAChG,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,CAAC;IACrC,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,OAAO,YAAY,CAAC;AACtB,CAAC","sourcesContent":["import React from 'react';\nimport { AccessibilityInfo } from 'react-native';\n\n/*** Track the cross-platform system reduced-motion preference for game presentation. */\nexport function useGameReducedMotion(): boolean {\n const [reduceMotion, setReduceMotion] = React.useState(false);\n\n React.useEffect(() => {\n void AccessibilityInfo.isReduceMotionEnabled().then(setReduceMotion);\n const subscription = AccessibilityInfo.addEventListener('reduceMotionChanged', setReduceMotion);\n return () => subscription.remove();\n }, []);\n\n return reduceMotion;\n}\n"]}
@@ -97,13 +97,13 @@ export interface GraphViewProps {
97
97
  export type GraphViewCallbacks = Pick<GraphViewProps, 'onEdgeEvent' | 'onLayoutComplete' | 'onNodeEvent' | 'onReady' | 'onViewportChange' | 'onSpacingFactorChange'>;
98
98
  /***
99
99
  * Render a browser graph while one runtime owns Cytoscape layout, viewport, and disposal.
100
- * @config zoomMode Use `fit-relative` to make controller zoom, events and min/max limits relative
100
+ * zoomMode Use `fit-relative` to make controller zoom, events and min/max limits relative
101
101
  * to the visible-node fit (1 = fit). The default `absolute` keeps engine-space zoom units.
102
- * @config sizeNodesToLabels Opt in to renderer-measured plain labels, including bold and Unicode
102
+ * sizeNodesToLabels Opt in to renderer-measured plain labels, including bold and Unicode
103
103
  * text. Keep padding in styleRules. Compound and rich-node dimensions retain their existing owners.
104
- * @config minReadableLabelSize Expand the manual zoom ceiling until plain labels reach this CSS-pixel size.
105
- * @config maxFitLabelSize Cap automatic fitting at this plain-label CSS-pixel size, leaving whitespace for tiny graphs.
106
- * @config onSpacingFactorChange Receive the spacing accepted by explicit fit({ optimizeSpacing: true }).
104
+ * minReadableLabelSize Expand the manual zoom ceiling until plain labels reach this CSS-pixel size.
105
+ * maxFitLabelSize Cap automatic fitting at this plain-label CSS-pixel size, leaving whitespace for tiny graphs.
106
+ * onSpacingFactorChange Receive the spacing accepted by explicit fit({ optimizeSpacing: true }).
107
107
  * Ordinary zoom never adjusts spacing or relayouts. Explicit optimization preserves layout ordering
108
108
  * and uses bounded collision checks including labels and compound siblings; it can recover uniformly
109
109
  * cramped layouts but cannot repair non-uniform overlaps.
@@ -3,13 +3,13 @@ import { createGraphRuntime } from './createGraphRuntime';
3
3
  import { GraphNodeOverlay } from './GraphNodeOverlay';
4
4
  /***
5
5
  * Render a browser graph while one runtime owns Cytoscape layout, viewport, and disposal.
6
- * @config zoomMode Use `fit-relative` to make controller zoom, events and min/max limits relative
6
+ * zoomMode Use `fit-relative` to make controller zoom, events and min/max limits relative
7
7
  * to the visible-node fit (1 = fit). The default `absolute` keeps engine-space zoom units.
8
- * @config sizeNodesToLabels Opt in to renderer-measured plain labels, including bold and Unicode
8
+ * sizeNodesToLabels Opt in to renderer-measured plain labels, including bold and Unicode
9
9
  * text. Keep padding in styleRules. Compound and rich-node dimensions retain their existing owners.
10
- * @config minReadableLabelSize Expand the manual zoom ceiling until plain labels reach this CSS-pixel size.
11
- * @config maxFitLabelSize Cap automatic fitting at this plain-label CSS-pixel size, leaving whitespace for tiny graphs.
12
- * @config onSpacingFactorChange Receive the spacing accepted by explicit fit({ optimizeSpacing: true }).
10
+ * minReadableLabelSize Expand the manual zoom ceiling until plain labels reach this CSS-pixel size.
11
+ * maxFitLabelSize Cap automatic fitting at this plain-label CSS-pixel size, leaving whitespace for tiny graphs.
12
+ * onSpacingFactorChange Receive the spacing accepted by explicit fit({ optimizeSpacing: true }).
13
13
  * Ordinary zoom never adjusts spacing or relayouts. Explicit optimization preserves layout ordering
14
14
  * and uses bounded collision checks including labels and compound siblings; it can recover uniformly
15
15
  * cramped layouts but cannot repair non-uniform overlaps.
@@ -1 +1 @@
1
- {"version":3,"file":"GraphView.js","sourceRoot":"","sources":["../../../../../../src/features/graph-view/adapters/inbound/web-artifact/GraphView.tsx"],"names":[],"mappings":"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","sourcesContent":["import type { CytoscapeOptions } from 'cytoscape';\nimport React from 'react';\n\nimport { createGraphRuntime, type GraphRuntime } from './createGraphRuntime';\nimport { GraphNodeOverlay } from './GraphNodeOverlay';\n\nexport type GraphViewLayoutName = 'breadthfirst' | 'circle' | 'concentric' | 'elk' | 'grid';\nexport type GraphViewElementEventType =\n 'press' | 'double-press' | 'select' | 'unselect' | 'pointer-enter' | 'pointer-leave';\n\nexport interface GraphViewNode {\n readonly id: string;\n readonly label?: string;\n readonly parentId?: string;\n readonly classes?: string;\n readonly data?: Readonly<Record<string, unknown>>;\n}\n\nexport interface GraphViewEdge {\n readonly id?: string;\n readonly source: string;\n readonly target: string;\n readonly classes?: string;\n readonly data?: Readonly<Record<string, unknown>>;\n}\n\nexport interface GraphViewStyleRule {\n readonly selector: string;\n readonly style: Readonly<Record<string, unknown>>;\n}\n\nexport interface GraphViewPoint {\n readonly x: number;\n readonly y: number;\n}\n\nexport interface GraphViewSize {\n readonly width: number;\n readonly height: number;\n}\n\nexport interface GraphViewNodeRenderContext {\n readonly hovered: boolean;\n readonly node: GraphViewNode;\n readonly selected: boolean;\n readonly zoom: number;\n}\n\nexport interface GraphViewRenderedNode {\n readonly hovered: boolean;\n readonly id: string;\n readonly position: GraphViewPoint;\n readonly selected: boolean;\n readonly zoom: number;\n}\n\nexport interface GraphViewViewport {\n readonly zoom: number;\n readonly pan: GraphViewPoint;\n}\n\nexport interface GraphViewFitOptions {\n /** Optimize existing layout spacing without rerunning its algorithm; whole-graph fits only. */\n readonly optimizeSpacing?: boolean;\n readonly nodeIds?: readonly string[];\n readonly padding?: number;\n}\n\nexport interface GraphViewElementEvent {\n readonly id: string;\n readonly type: GraphViewElementEventType;\n}\n\nexport interface GraphViewController {\n fit(options?: GraphViewFitOptions): void;\n getViewport(): GraphViewViewport;\n getZoomRange(): { readonly min: number; readonly max: number };\n setPan(pan: GraphViewPoint): void;\n setZoom(zoom: number): void;\n zoomBy(factor: number): void;\n}\n\nexport interface GraphViewProps {\n readonly nodes: readonly GraphViewNode[];\n readonly edges: readonly GraphViewEdge[];\n readonly layout?: GraphViewLayoutName;\n readonly layoutOptions?: Readonly<Record<string, unknown>>;\n readonly spacingFactor?: number;\n readonly styleRules?: readonly GraphViewStyleRule[];\n readonly selectedNodeIds?: readonly string[];\n readonly renderNode?: (context: GraphViewNodeRenderContext) => React.ReactNode;\n readonly getNodeSize?: (node: GraphViewNode) => GraphViewSize | undefined;\n readonly fitPadding?: number;\n readonly minZoom?: number;\n readonly maxZoom?: number;\n readonly minReadableLabelSize?: number;\n readonly maxFitLabelSize?: number;\n /** Zoom values and bounds use the full-node fit as 1 when fit-relative is selected. */\n readonly zoomMode?: 'absolute' | 'fit-relative';\n /** Measure plain labels before layout instead of estimating width from character count. */\n readonly sizeNodesToLabels?: boolean;\n readonly className?: string;\n readonly style?: React.CSSProperties;\n readonly ariaLabel?: string;\n readonly onReady?: (controller: GraphViewController) => void;\n readonly onLayoutComplete?: (controller: GraphViewController) => void;\n readonly onNodeEvent?: (event: GraphViewElementEvent) => void;\n readonly onEdgeEvent?: (event: GraphViewElementEvent) => void;\n readonly onViewportChange?: (viewport: GraphViewViewport) => void;\n readonly onSpacingFactorChange?: (spacingFactor: number) => void;\n}\n\nexport type GraphViewCallbacks = Pick<\n GraphViewProps,\n | 'onEdgeEvent'\n | 'onLayoutComplete'\n | 'onNodeEvent'\n | 'onReady'\n | 'onViewportChange'\n | 'onSpacingFactorChange'\n>;\n\ntype GraphContainer = NonNullable<CytoscapeOptions['container']>;\n\n/***\n * Render a browser graph while one runtime owns Cytoscape layout, viewport, and disposal.\n * @config zoomMode Use `fit-relative` to make controller zoom, events and min/max limits relative\n * to the visible-node fit (1 = fit). The default `absolute` keeps engine-space zoom units.\n * @config sizeNodesToLabels Opt in to renderer-measured plain labels, including bold and Unicode\n * text. Keep padding in styleRules. Compound and rich-node dimensions retain their existing owners.\n * @config minReadableLabelSize Expand the manual zoom ceiling until plain labels reach this CSS-pixel size.\n * @config maxFitLabelSize Cap automatic fitting at this plain-label CSS-pixel size, leaving whitespace for tiny graphs.\n * @config onSpacingFactorChange Receive the spacing accepted by explicit fit({ optimizeSpacing: true }).\n * Ordinary zoom never adjusts spacing or relayouts. Explicit optimization preserves layout ordering\n * and uses bounded collision checks including labels and compound siblings; it can recover uniformly\n * cramped layouts but cannot repair non-uniform overlaps.\n */\nexport function GraphView(props: GraphViewProps) {\n const { containerRef, renderedNodes, runtimeRef } = useGraphViewRuntime(props);\n\n return (\n <div\n aria-label={props.ariaLabel ?? 'Graph'}\n className={props.className}\n role=\"application\"\n style={{\n height: '100%',\n minHeight: 0,\n minWidth: 0,\n position: 'relative',\n width: '100%',\n ...props.style,\n }}\n >\n <div ref={containerRef} style={{ height: '100%', width: '100%' }} />\n {props.renderNode ? (\n <GraphNodeOverlay\n nodes={props.nodes}\n renderedNodes={renderedNodes}\n renderNode={props.renderNode}\n onNodeEvent={(id, type) => runtimeRef.current?.handleOverlayNodeEvent(id, type)}\n onNodeSize={(id, size) => runtimeRef.current?.setNodeSize(id, size)}\n />\n ) : null}\n </div>\n );\n}\n\n/*** Compose React synchronization around the single imperative graph runtime. */\nfunction useGraphViewRuntime(props: GraphViewProps) {\n const containerRef = React.useRef<GraphContainer | null>(null);\n const runtimeRef = React.useRef<GraphRuntime | null>(null);\n const callbacksRef = useGraphCallbacksRef(props);\n const [renderedNodes, setRenderedNodes] = React.useState<readonly GraphViewRenderedNode[]>([]);\n\n useRuntimeLifecycle(containerRef, runtimeRef, callbacksRef);\n useRuntimeGraphUpdate(runtimeRef, props);\n useRuntimeSelection(runtimeRef, props.selectedNodeIds);\n useRenderedNodeSubscription(runtimeRef, props.renderNode, setRenderedNodes);\n useKnownNodeSizes(runtimeRef, props.nodes, props.getNodeSize);\n\n return { containerRef, renderedNodes, runtimeRef };\n}\n\n/*** Keep the callback ref current without mutating refs during render. */\nfunction useGraphCallbacksRef(props: GraphViewProps) {\n const callbacksRef = React.useRef<GraphViewCallbacks>(readCallbacks(props));\n const {\n onEdgeEvent,\n onLayoutComplete,\n onNodeEvent,\n onReady,\n onViewportChange,\n onSpacingFactorChange,\n } = props;\n\n React.useEffect(() => {\n callbacksRef.current = {\n onEdgeEvent,\n onLayoutComplete,\n onNodeEvent,\n onReady,\n onViewportChange,\n onSpacingFactorChange,\n };\n }, [\n onEdgeEvent,\n onLayoutComplete,\n onNodeEvent,\n onReady,\n onViewportChange,\n onSpacingFactorChange,\n ]);\n\n return callbacksRef;\n}\n\n/*** Create and dispose the runtime only with the underlying browser container lifetime. */\nfunction useRuntimeLifecycle(\n containerRef: { current: GraphContainer | null },\n runtimeRef: { current: GraphRuntime | null },\n callbacksRef: { current: GraphViewCallbacks },\n) {\n React.useEffect(() => {\n const container = containerRef.current;\n if (container === null) return;\n const runtime = createGraphRuntime(container, callbacksRef);\n runtimeRef.current = runtime;\n return () => {\n runtime.destroy();\n runtimeRef.current = null;\n };\n }, [callbacksRef, containerRef, runtimeRef]);\n}\n\n/*** Synchronize graph data and layout policy without exposing Cytoscape to React. */\nfunction useRuntimeGraphUpdate(\n runtimeRef: { current: GraphRuntime | null },\n props: GraphViewProps,\n) {\n const {\n edges,\n fitPadding,\n layout,\n layoutOptions,\n maxZoom,\n minReadableLabelSize,\n maxFitLabelSize,\n minZoom,\n zoomMode,\n sizeNodesToLabels,\n nodes,\n renderNode,\n spacingFactor,\n styleRules,\n } = props;\n\n React.useEffect(() => {\n runtimeRef.current?.update({\n edges,\n fitPadding,\n layout,\n layoutOptions,\n maxZoom,\n minReadableLabelSize,\n maxFitLabelSize,\n minZoom,\n zoomMode,\n sizeNodesToLabels,\n nodes,\n richNodeRendering: renderNode !== undefined,\n spacingFactor,\n styleRules,\n });\n }, [\n edges,\n fitPadding,\n layout,\n layoutOptions,\n maxZoom,\n minReadableLabelSize,\n maxFitLabelSize,\n minZoom,\n zoomMode,\n sizeNodesToLabels,\n nodes,\n renderNode,\n runtimeRef,\n spacingFactor,\n styleRules,\n ]);\n}\n\n/*** Synchronize optional controlled selection independently from graph layout. */\nfunction useRuntimeSelection(\n runtimeRef: { current: GraphRuntime | null },\n selectedNodeIds: readonly string[] | undefined,\n) {\n React.useEffect(() => {\n runtimeRef.current?.setSelectedNodeIds(selectedNodeIds);\n }, [runtimeRef, selectedNodeIds]);\n}\n\n/*** Subscribe the optional rich-node overlay to rendered runtime positions. */\nfunction useRenderedNodeSubscription(\n runtimeRef: { current: GraphRuntime | null },\n renderNode: GraphViewProps['renderNode'],\n setRenderedNodes: (nodes: readonly GraphViewRenderedNode[]) => void,\n) {\n React.useEffect(() => {\n const runtime = runtimeRef.current;\n if (runtime === null || renderNode === undefined) {\n setRenderedNodes([]);\n return;\n }\n return runtime.subscribeRenderedNodes(setRenderedNodes);\n }, [renderNode, runtimeRef, setRenderedNodes]);\n}\n\n/*** Seed known rich-node dimensions without requiring DOM measurement. */\nfunction useKnownNodeSizes(\n runtimeRef: { current: GraphRuntime | null },\n nodes: readonly GraphViewNode[],\n getNodeSize: GraphViewProps['getNodeSize'],\n) {\n React.useEffect(() => {\n const runtime = runtimeRef.current;\n if (runtime === null || getNodeSize === undefined) return;\n for (const node of nodes) {\n const size = getNodeSize(node);\n if (size) runtime.setNodeSize(node.id, size);\n }\n }, [getNodeSize, nodes, runtimeRef]);\n}\n\n/*** Read callback props for the initial runtime callback-ref value. */\nfunction readCallbacks(props: GraphViewProps): GraphViewCallbacks {\n return {\n onEdgeEvent: props.onEdgeEvent,\n onLayoutComplete: props.onLayoutComplete,\n onNodeEvent: props.onNodeEvent,\n onReady: props.onReady,\n onViewportChange: props.onViewportChange,\n onSpacingFactorChange: props.onSpacingFactorChange,\n };\n}\n"]}
1
+ {"version":3,"file":"GraphView.js","sourceRoot":"","sources":["../../../../../../src/features/graph-view/adapters/inbound/web-artifact/GraphView.tsx"],"names":[],"mappings":"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","sourcesContent":["import type { CytoscapeOptions } from 'cytoscape';\nimport React from 'react';\n\nimport { createGraphRuntime, type GraphRuntime } from './createGraphRuntime';\nimport { GraphNodeOverlay } from './GraphNodeOverlay';\n\nexport type GraphViewLayoutName = 'breadthfirst' | 'circle' | 'concentric' | 'elk' | 'grid';\nexport type GraphViewElementEventType =\n 'press' | 'double-press' | 'select' | 'unselect' | 'pointer-enter' | 'pointer-leave';\n\nexport interface GraphViewNode {\n readonly id: string;\n readonly label?: string;\n readonly parentId?: string;\n readonly classes?: string;\n readonly data?: Readonly<Record<string, unknown>>;\n}\n\nexport interface GraphViewEdge {\n readonly id?: string;\n readonly source: string;\n readonly target: string;\n readonly classes?: string;\n readonly data?: Readonly<Record<string, unknown>>;\n}\n\nexport interface GraphViewStyleRule {\n readonly selector: string;\n readonly style: Readonly<Record<string, unknown>>;\n}\n\nexport interface GraphViewPoint {\n readonly x: number;\n readonly y: number;\n}\n\nexport interface GraphViewSize {\n readonly width: number;\n readonly height: number;\n}\n\nexport interface GraphViewNodeRenderContext {\n readonly hovered: boolean;\n readonly node: GraphViewNode;\n readonly selected: boolean;\n readonly zoom: number;\n}\n\nexport interface GraphViewRenderedNode {\n readonly hovered: boolean;\n readonly id: string;\n readonly position: GraphViewPoint;\n readonly selected: boolean;\n readonly zoom: number;\n}\n\nexport interface GraphViewViewport {\n readonly zoom: number;\n readonly pan: GraphViewPoint;\n}\n\nexport interface GraphViewFitOptions {\n /** Optimize existing layout spacing without rerunning its algorithm; whole-graph fits only. */\n readonly optimizeSpacing?: boolean;\n readonly nodeIds?: readonly string[];\n readonly padding?: number;\n}\n\nexport interface GraphViewElementEvent {\n readonly id: string;\n readonly type: GraphViewElementEventType;\n}\n\nexport interface GraphViewController {\n fit(options?: GraphViewFitOptions): void;\n getViewport(): GraphViewViewport;\n getZoomRange(): { readonly min: number; readonly max: number };\n setPan(pan: GraphViewPoint): void;\n setZoom(zoom: number): void;\n zoomBy(factor: number): void;\n}\n\nexport interface GraphViewProps {\n readonly nodes: readonly GraphViewNode[];\n readonly edges: readonly GraphViewEdge[];\n readonly layout?: GraphViewLayoutName;\n readonly layoutOptions?: Readonly<Record<string, unknown>>;\n readonly spacingFactor?: number;\n readonly styleRules?: readonly GraphViewStyleRule[];\n readonly selectedNodeIds?: readonly string[];\n readonly renderNode?: (context: GraphViewNodeRenderContext) => React.ReactNode;\n readonly getNodeSize?: (node: GraphViewNode) => GraphViewSize | undefined;\n readonly fitPadding?: number;\n readonly minZoom?: number;\n readonly maxZoom?: number;\n readonly minReadableLabelSize?: number;\n readonly maxFitLabelSize?: number;\n /** Zoom values and bounds use the full-node fit as 1 when fit-relative is selected. */\n readonly zoomMode?: 'absolute' | 'fit-relative';\n /** Measure plain labels before layout instead of estimating width from character count. */\n readonly sizeNodesToLabels?: boolean;\n readonly className?: string;\n readonly style?: React.CSSProperties;\n readonly ariaLabel?: string;\n readonly onReady?: (controller: GraphViewController) => void;\n readonly onLayoutComplete?: (controller: GraphViewController) => void;\n readonly onNodeEvent?: (event: GraphViewElementEvent) => void;\n readonly onEdgeEvent?: (event: GraphViewElementEvent) => void;\n readonly onViewportChange?: (viewport: GraphViewViewport) => void;\n readonly onSpacingFactorChange?: (spacingFactor: number) => void;\n}\n\nexport type GraphViewCallbacks = Pick<\n GraphViewProps,\n | 'onEdgeEvent'\n | 'onLayoutComplete'\n | 'onNodeEvent'\n | 'onReady'\n | 'onViewportChange'\n | 'onSpacingFactorChange'\n>;\n\ntype GraphContainer = NonNullable<CytoscapeOptions['container']>;\n\n/***\n * Render a browser graph while one runtime owns Cytoscape layout, viewport, and disposal.\n * zoomMode Use `fit-relative` to make controller zoom, events and min/max limits relative\n * to the visible-node fit (1 = fit). The default `absolute` keeps engine-space zoom units.\n * sizeNodesToLabels Opt in to renderer-measured plain labels, including bold and Unicode\n * text. Keep padding in styleRules. Compound and rich-node dimensions retain their existing owners.\n * minReadableLabelSize Expand the manual zoom ceiling until plain labels reach this CSS-pixel size.\n * maxFitLabelSize Cap automatic fitting at this plain-label CSS-pixel size, leaving whitespace for tiny graphs.\n * onSpacingFactorChange Receive the spacing accepted by explicit fit({ optimizeSpacing: true }).\n * Ordinary zoom never adjusts spacing or relayouts. Explicit optimization preserves layout ordering\n * and uses bounded collision checks including labels and compound siblings; it can recover uniformly\n * cramped layouts but cannot repair non-uniform overlaps.\n */\nexport function GraphView(props: GraphViewProps) {\n const { containerRef, renderedNodes, runtimeRef } = useGraphViewRuntime(props);\n\n return (\n <div\n aria-label={props.ariaLabel ?? 'Graph'}\n className={props.className}\n role=\"application\"\n style={{\n height: '100%',\n minHeight: 0,\n minWidth: 0,\n position: 'relative',\n width: '100%',\n ...props.style,\n }}\n >\n <div ref={containerRef} style={{ height: '100%', width: '100%' }} />\n {props.renderNode ? (\n <GraphNodeOverlay\n nodes={props.nodes}\n renderedNodes={renderedNodes}\n renderNode={props.renderNode}\n onNodeEvent={(id, type) => runtimeRef.current?.handleOverlayNodeEvent(id, type)}\n onNodeSize={(id, size) => runtimeRef.current?.setNodeSize(id, size)}\n />\n ) : null}\n </div>\n );\n}\n\n/*** Compose React synchronization around the single imperative graph runtime. */\nfunction useGraphViewRuntime(props: GraphViewProps) {\n const containerRef = React.useRef<GraphContainer | null>(null);\n const runtimeRef = React.useRef<GraphRuntime | null>(null);\n const callbacksRef = useGraphCallbacksRef(props);\n const [renderedNodes, setRenderedNodes] = React.useState<readonly GraphViewRenderedNode[]>([]);\n\n useRuntimeLifecycle(containerRef, runtimeRef, callbacksRef);\n useRuntimeGraphUpdate(runtimeRef, props);\n useRuntimeSelection(runtimeRef, props.selectedNodeIds);\n useRenderedNodeSubscription(runtimeRef, props.renderNode, setRenderedNodes);\n useKnownNodeSizes(runtimeRef, props.nodes, props.getNodeSize);\n\n return { containerRef, renderedNodes, runtimeRef };\n}\n\n/*** Keep the callback ref current without mutating refs during render. */\nfunction useGraphCallbacksRef(props: GraphViewProps) {\n const callbacksRef = React.useRef<GraphViewCallbacks>(readCallbacks(props));\n const {\n onEdgeEvent,\n onLayoutComplete,\n onNodeEvent,\n onReady,\n onViewportChange,\n onSpacingFactorChange,\n } = props;\n\n React.useEffect(() => {\n callbacksRef.current = {\n onEdgeEvent,\n onLayoutComplete,\n onNodeEvent,\n onReady,\n onViewportChange,\n onSpacingFactorChange,\n };\n }, [\n onEdgeEvent,\n onLayoutComplete,\n onNodeEvent,\n onReady,\n onViewportChange,\n onSpacingFactorChange,\n ]);\n\n return callbacksRef;\n}\n\n/*** Create and dispose the runtime only with the underlying browser container lifetime. */\nfunction useRuntimeLifecycle(\n containerRef: { current: GraphContainer | null },\n runtimeRef: { current: GraphRuntime | null },\n callbacksRef: { current: GraphViewCallbacks },\n) {\n React.useEffect(() => {\n const container = containerRef.current;\n if (container === null) return;\n const runtime = createGraphRuntime(container, callbacksRef);\n runtimeRef.current = runtime;\n return () => {\n runtime.destroy();\n runtimeRef.current = null;\n };\n }, [callbacksRef, containerRef, runtimeRef]);\n}\n\n/*** Synchronize graph data and layout policy without exposing Cytoscape to React. */\nfunction useRuntimeGraphUpdate(\n runtimeRef: { current: GraphRuntime | null },\n props: GraphViewProps,\n) {\n const {\n edges,\n fitPadding,\n layout,\n layoutOptions,\n maxZoom,\n minReadableLabelSize,\n maxFitLabelSize,\n minZoom,\n zoomMode,\n sizeNodesToLabels,\n nodes,\n renderNode,\n spacingFactor,\n styleRules,\n } = props;\n\n React.useEffect(() => {\n runtimeRef.current?.update({\n edges,\n fitPadding,\n layout,\n layoutOptions,\n maxZoom,\n minReadableLabelSize,\n maxFitLabelSize,\n minZoom,\n zoomMode,\n sizeNodesToLabels,\n nodes,\n richNodeRendering: renderNode !== undefined,\n spacingFactor,\n styleRules,\n });\n }, [\n edges,\n fitPadding,\n layout,\n layoutOptions,\n maxZoom,\n minReadableLabelSize,\n maxFitLabelSize,\n minZoom,\n zoomMode,\n sizeNodesToLabels,\n nodes,\n renderNode,\n runtimeRef,\n spacingFactor,\n styleRules,\n ]);\n}\n\n/*** Synchronize optional controlled selection independently from graph layout. */\nfunction useRuntimeSelection(\n runtimeRef: { current: GraphRuntime | null },\n selectedNodeIds: readonly string[] | undefined,\n) {\n React.useEffect(() => {\n runtimeRef.current?.setSelectedNodeIds(selectedNodeIds);\n }, [runtimeRef, selectedNodeIds]);\n}\n\n/*** Subscribe the optional rich-node overlay to rendered runtime positions. */\nfunction useRenderedNodeSubscription(\n runtimeRef: { current: GraphRuntime | null },\n renderNode: GraphViewProps['renderNode'],\n setRenderedNodes: (nodes: readonly GraphViewRenderedNode[]) => void,\n) {\n React.useEffect(() => {\n const runtime = runtimeRef.current;\n if (runtime === null || renderNode === undefined) {\n setRenderedNodes([]);\n return;\n }\n return runtime.subscribeRenderedNodes(setRenderedNodes);\n }, [renderNode, runtimeRef, setRenderedNodes]);\n}\n\n/*** Seed known rich-node dimensions without requiring DOM measurement. */\nfunction useKnownNodeSizes(\n runtimeRef: { current: GraphRuntime | null },\n nodes: readonly GraphViewNode[],\n getNodeSize: GraphViewProps['getNodeSize'],\n) {\n React.useEffect(() => {\n const runtime = runtimeRef.current;\n if (runtime === null || getNodeSize === undefined) return;\n for (const node of nodes) {\n const size = getNodeSize(node);\n if (size) runtime.setNodeSize(node.id, size);\n }\n }, [getNodeSize, nodes, runtimeRef]);\n}\n\n/*** Read callback props for the initial runtime callback-ref value. */\nfunction readCallbacks(props: GraphViewProps): GraphViewCallbacks {\n return {\n onEdgeEvent: props.onEdgeEvent,\n onLayoutComplete: props.onLayoutComplete,\n onNodeEvent: props.onNodeEvent,\n onReady: props.onReady,\n onViewportChange: props.onViewportChange,\n onSpacingFactorChange: props.onSpacingFactorChange,\n };\n}\n"]}
@@ -2,7 +2,7 @@ import type { Core } from 'cytoscape';
2
2
  /***
3
3
  * Optimize settled layout spacing around readable label bounds instead of full node clearance.
4
4
  * Compound containment stays intentional while sibling groups retain non-overlapping boundaries.
5
- * @performance Cytoscape geometry is measured once, then bounded pure numeric trials reuse the
5
+ * Cytoscape geometry is measured once, then bounded pure numeric trials reuse the
6
6
  * immutable snapshot. No layout reruns, zoom work, or intermediate frames are painted.
7
7
  */
8
8
  export declare function compactGraphSpacing(cy: Core, spacingFactor: number): number;
@@ -7,7 +7,7 @@ const SEARCH_ITERATIONS = 8;
7
7
  /***
8
8
  * Optimize settled layout spacing around readable label bounds instead of full node clearance.
9
9
  * Compound containment stays intentional while sibling groups retain non-overlapping boundaries.
10
- * @performance Cytoscape geometry is measured once, then bounded pure numeric trials reuse the
10
+ * Cytoscape geometry is measured once, then bounded pure numeric trials reuse the
11
11
  * immutable snapshot. No layout reruns, zoom work, or intermediate frames are painted.
12
12
  */
13
13
  export function compactGraphSpacing(cy, spacingFactor) {
@@ -1 +1 @@
1
- {"version":3,"file":"compactGraphSpacing.js","sourceRoot":"","sources":["../../../../../../src/features/graph-view/adapters/inbound/web-artifact/compactGraphSpacing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,MAAM,+BAA+B,CAAC;AAG1E,MAAM,mBAAmB,GAAG,IAAI,CAAC;AACjC,MAAM,sBAAsB,GAAG,CAAC,CAAC;AACjC,MAAM,cAAc,GAAG,IAAI,CAAC;AAC5B,MAAM,eAAe,GAAG,MAAM,CAAC;AAC/B,MAAM,iBAAiB,GAAG,CAAC,CAAC;AAE5B;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,EAAQ,EAAE,aAAqB;IACjE,MAAM,MAAM,GAAG,EAAE,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;IACtC,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,CAAC,MAAM,GAAG,cAAc,IAAI,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,MAAM,GAAG,CAAC;QAC3F,OAAO,aAAa,CAAC;IAEvB,MAAM,MAAM,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC;IACpC,MAAM,MAAM,GAAG,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,GAAG,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,GAAG,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC;IAClF,MAAM,YAAY,GAAG,MAAM,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;IAClD,MAAM,MAAM,GAAG,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAC9C,iBAAiB,CACf,IAAI,CAAC,EAAE,EAAE,EACT,IAAI,CAAC,SAAS,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC,EAC7C,IAAI,CAAC,WAAW,EAAE,EAClB,YAAY,CACb,CACF,CAAC;IACF,MAAM,OAAO,GAAG,CAAC,MAAc,EAAE,EAAE,CACjC,CAAC,mBAAmB,CAAC,qBAAqB,CAAC,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACpF,MAAM,eAAe,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IACnC,MAAM,OAAO,GAAG,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACvE,MAAM,OAAO,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,oBAAoB,CAAC,OAAO,CAAC,CAAC;IACpE,IAAI,OAAO,KAAK,SAAS;QAAE,OAAO,aAAa,CAAC;IAEhD,MAAM,MAAM,GAAG,yBAAyB,CAAC;QACvC,OAAO;QACP,OAAO;QACP,UAAU,EAAE,iBAAiB;QAC7B,OAAO;KACR,CAAC,CAAC;IACH,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,aAAa,CAAC;IAE/C,UAAU,CAAC,EAAE,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7C,OAAO,aAAa,GAAG,MAAM,CAAC;AAChC,CAAC;AA6CD,2FAA2F;AAC3F,SAAS,gBAAgB,CAAC,IAAkB;IAC1C,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC;QAC/B,aAAa,EAAE,IAAI;QACnB,eAAe,EAAE,KAAK;QACtB,gBAAgB,EAAE,KAAK;KACxB,CAAC,CAAC;IACH,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC;QAChC,YAAY,EAAE,KAAK;QACnB,YAAY,EAAE,KAAK;QACnB,aAAa,EAAE,IAAI;QACnB,eAAe,EAAE,KAAK;QACtB,gBAAgB,EAAE,KAAK;KACxB,CAAC,CAAC;IACH,OAAO;QACL,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE;QACb,SAAS,EAAE,IAAI,GAAG,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC;QACjE,QAAQ,EAAE,EAAE,GAAG,IAAI,CAAC,QAAQ,EAAE,EAAE;QAChC,QAAQ,EAAE,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO;QACpD,OAAO;KACR,CAAC;AACJ,CAAC;AAED,kGAAkG;AAClG,SAAS,iBAAiB,CACxB,EAAU,EACV,WAA8B,EAC9B,SAAiB,EACjB,MAA+B;IAE/B,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IACpE,MAAM,eAAe,GAAG,WAAW,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,SAAS,CAAC;IAC1F,OAAO;QACL,EAAE;QACF,SAAS,EAAE,IAAI,GAAG,CAAC,WAAW,CAAC;QAC/B,WAAW;QACX,MAAM,EAAE;YACN,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,eAAe,CAAC,EAAE,GAAG,SAAS,CAAC,EAAE,CAAC;YACpD,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,CAAC,EAAE,GAAG,eAAe,CAAC,EAAE,CAAC;YACrD,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,eAAe,CAAC,EAAE,GAAG,SAAS,CAAC,EAAE,CAAC;YACnD,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,CAAC,EAAE,GAAG,eAAe,CAAC,EAAE,CAAC;SACvD;KACF,CAAC;AACJ,CAAC;AAED,4FAA4F;AAC5F,SAAS,qBAAqB,CAC5B,MAA+B,EAC/B,MAAgC,EAChC,MAAa,EACb,MAAc;IAEd,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QACnC,EAAE,EAAE,IAAI,CAAC,EAAE;QACX,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,IAAI,EAAE,OAAgB;QACtB,GAAG,EAAE,WAAW,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC;KAC/D,CAAC,CAAC,CAAC;IACJ,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE;QAC7C,MAAM,WAAW,GAAG,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CACjD,WAAW,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,CACzD,CAAC;QACF,MAAM,KAAK,GAAG,WAAW,CAAC,WAAW,CAAC,CAAC;QACvC,IAAI,CAAC,KAAK;YAAE,OAAO,EAAE,CAAC;QACtB,OAAO;YACL;gBACE,EAAE,EAAE,KAAK,CAAC,EAAE;gBACZ,SAAS,EAAE,KAAK,CAAC,SAAS;gBAC1B,IAAI,EAAE,OAAgB;gBACtB,GAAG,EAAE,YAAY,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC;aACvC;SACF,CAAC;IACJ,CAAC,CAAC,CAAC;IACH,OAAO,CAAC,GAAG,MAAM,EAAE,GAAG,aAAa,CAAC,CAAC;AACvC,CAAC;AAED,iGAAiG;AACjG,SAAS,oBAAoB,CAAC,OAAoC;IAChE,OAAO,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,sBAAsB,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CACxF,OAAO,CACR,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,SAAS,mBAAmB,CAAC,KAA8B;IACzD,MAAM,MAAM,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,GAAG,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChF,MAAM,MAAM,GAAG,EAAE,SAAS,EAAE,eAAe,EAAE,CAAC;IAC9C,KAAK,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC;QAC9C,KAAK,IAAI,IAAI,GAAG,KAAK,GAAG,CAAC,EAAE,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,IAAI,IAAI,CAAC,EAAE,CAAC;YAC3D,MAAM,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;YAC/B,IAAI,CAAC,MAAM;gBAAE,MAAM;YACnB,IAAI,MAAM,CAAC,GAAG,CAAC,EAAE,IAAI,KAAK,CAAC,GAAG,CAAC,EAAE;gBAAE,MAAM;YACzC,MAAM,CAAC,SAAS,IAAI,CAAC,CAAC;YACtB,IAAI,MAAM,CAAC,SAAS,GAAG,CAAC;gBAAE,OAAO,IAAI,CAAC;YACtC,IAAI,wBAAwB,CAAC,KAAK,EAAE,MAAM,CAAC;gBAAE,SAAS;YACtD,IAAI,eAAe,CAAC,KAAK,EAAE,MAAM,CAAC;gBAAE,OAAO,IAAI,CAAC;QAClD,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,iGAAiG;AACjG,SAAS,wBAAwB,CAAC,KAAmB,EAAE,MAAoB;IACzE,OAAO,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;AAC1E,CAAC;AAED,iGAAiG;AACjG,SAAS,eAAe,CAAC,KAAmB,EAAE,MAAoB;IAChE,MAAM,YAAY,GAChB,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChF,MAAM,aAAa,GACjB,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChF,IAAI,YAAY,IAAI,CAAC,IAAI,aAAa,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IAC1D,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,IAAI,MAAM,CAAC,IAAI,KAAK,OAAO;QAAE,OAAO,IAAI,CAAC;IACnE,MAAM,UAAU,GAAG,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IACtE,MAAM,WAAW,GAAG,aAAa,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IACxE,OAAO,UAAU,GAAG,mBAAmB,IAAI,WAAW,GAAG,mBAAmB,CAAC;AAC/E,CAAC;AAED,uFAAuF;AACvF,SAAS,WAAW,CAAC,GAAW,EAAE,QAAe,EAAE,MAAa,EAAE,MAAc;IAC9E,MAAM,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAClD,MAAM,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAClD,OAAO;QACL,EAAE,EAAE,GAAG,CAAC,EAAE,GAAG,EAAE;QACf,EAAE,EAAE,GAAG,CAAC,EAAE,GAAG,EAAE;QACf,EAAE,EAAE,GAAG,CAAC,EAAE,GAAG,EAAE;QACf,EAAE,EAAE,GAAG,CAAC,EAAE,GAAG,EAAE;QACf,CAAC,EAAE,GAAG,CAAC,CAAC;QACR,CAAC,EAAE,GAAG,CAAC,CAAC;KACT,CAAC;AACJ,CAAC;AAED,mFAAmF;AACnF,SAAS,YAAY,CAAC,GAAW,EAAE,MAAc;IAC/C,MAAM,EAAE,GAAG,GAAG,CAAC,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC;IAChC,MAAM,EAAE,GAAG,GAAG,CAAC,EAAE,GAAG,MAAM,CAAC,GAAG,CAAC;IAC/B,MAAM,EAAE,GAAG,GAAG,CAAC,EAAE,GAAG,MAAM,CAAC,KAAK,CAAC;IACjC,MAAM,EAAE,GAAG,GAAG,CAAC,EAAE,GAAG,MAAM,CAAC,MAAM,CAAC;IAClC,OAAO,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC;AACpD,CAAC;AAED,2FAA2F;AAC3F,SAAS,WAAW,CAAC,KAAwB;IAC3C,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IACzC,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IACnD,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IACnD,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IACnD,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IACnD,OAAO,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC;AACpD,CAAC;AAED,2EAA2E;AAC3E,SAAS,WAAW,CAAC,GAAW;IAC9B,OAAO,GAAG,CAAC,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;AAChC,CAAC;AAED,sGAAsG;AACtG,SAAS,UAAU,CACjB,EAAQ,EACR,MAA+B,EAC/B,MAAa,EACb,MAAc;IAEd,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IAC1E,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE;QACZ,EAAE,CAAC,KAAK,EAAE;aACP,GAAG,CAAC,SAAS,CAAC;aACd,SAAS,CAAC,CAAC,IAAI,EAAE,EAAE;YAClB,MAAM,QAAQ,GAAG,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAC7D,OAAO;gBACL,CAAC,EAAE,MAAM,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM;gBAC9C,CAAC,EAAE,MAAM,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM;aAC/C,CAAC;QACJ,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;AACL,CAAC","sourcesContent":["import { findMinimumAcceptedNumber } from '@ankhorage/utility/algorithms';\nimport type { Core, NodeSingular } from 'cytoscape';\n\nconst LABEL_OVERLAP_RATIO = 0.12;\nconst MAX_EXPANSION_ATTEMPTS = 8;\nconst MAX_NODE_COUNT = 2000;\nconst MAX_PAIR_CHECKS = 200000;\nconst SEARCH_ITERATIONS = 8;\n\n/***\n * Optimize settled layout spacing around readable label bounds instead of full node clearance.\n * Compound containment stays intentional while sibling groups retain non-overlapping boundaries.\n * @performance Cytoscape geometry is measured once, then bounded pure numeric trials reuse the\n * immutable snapshot. No layout reruns, zoom work, or intermediate frames are painted.\n */\nexport function compactGraphSpacing(cy: Core, spacingFactor: number): number {\n const leaves = cy.nodes(':childless');\n if (leaves.length < 2 || cy.nodes().length > MAX_NODE_COUNT || cy.nodes(':locked').length > 0)\n return spacingFactor;\n\n const bounds = leaves.boundingBox();\n const center = { x: (bounds.x1 + bounds.x2) / 2, y: (bounds.y1 + bounds.y2) / 2 };\n const leafGeometry = leaves.map(readLeafGeometry);\n const groups = cy.nodes(':parent').map((node) =>\n readGroupGeometry(\n node.id(),\n node.ancestors().map((parent) => parent.id()),\n node.boundingBox(),\n leafGeometry,\n ),\n );\n const accepts = (factor: number) =>\n !hasUnsafeCollisions(resolveCollisionBoxes(leafGeometry, groups, center, factor));\n const currentAccepted = accepts(1);\n const minimum = currentAccepted ? Math.min(1, 0.1 / spacingFactor) : 1;\n const maximum = currentAccepted ? 1 : findExpansionMaximum(accepts);\n if (maximum === undefined) return spacingFactor;\n\n const factor = findMinimumAcceptedNumber({\n minimum,\n maximum,\n iterations: SEARCH_ITERATIONS,\n accepts,\n });\n if (factor === undefined) return spacingFactor;\n\n applyScale(cy, leafGeometry, center, factor);\n return spacingFactor * factor;\n}\n\ninterface Point {\n readonly x: number;\n readonly y: number;\n}\n\ninterface Bounds {\n readonly x1: number;\n readonly y1: number;\n readonly x2: number;\n readonly y2: number;\n readonly w: number;\n readonly h: number;\n}\n\ninterface Insets {\n readonly left: number;\n readonly right: number;\n readonly top: number;\n readonly bottom: number;\n}\n\ninterface LeafGeometry {\n readonly id: string;\n readonly ancestors: ReadonlySet<string>;\n readonly position: Point;\n readonly labelBox: Bounds;\n readonly nodeBox: Bounds;\n}\n\ninterface GroupGeometry {\n readonly id: string;\n readonly ancestors: ReadonlySet<string>;\n readonly descendants: readonly LeafGeometry[];\n readonly insets: Insets;\n}\n\ninterface CollisionBox {\n readonly id: string;\n readonly ancestors: ReadonlySet<string>;\n readonly kind: 'label' | 'group';\n readonly box: Bounds;\n}\n\n/*** Read one leaf's immutable position, hierarchy and renderer-measured label geometry. */\nfunction readLeafGeometry(node: NodeSingular): LeafGeometry {\n const nodeBox = node.boundingBox({\n includeLabels: true,\n includeOverlays: false,\n includeUnderlays: false,\n });\n const labelBox = node.boundingBox({\n includeNodes: false,\n includeEdges: false,\n includeLabels: true,\n includeOverlays: false,\n includeUnderlays: false,\n });\n return {\n id: node.id(),\n ancestors: new Set(node.ancestors().map((parent) => parent.id())),\n position: { ...node.position() },\n labelBox: isUsableBox(labelBox) ? labelBox : nodeBox,\n nodeBox,\n };\n}\n\n/*** Capture one compound group's descendant geometry and constant renderer-owned outer insets. */\nfunction readGroupGeometry(\n id: string,\n ancestorIds: readonly string[],\n parentBox: Bounds,\n leaves: readonly LeafGeometry[],\n): GroupGeometry {\n const descendants = leaves.filter((leaf) => leaf.ancestors.has(id));\n const descendantUnion = unionBounds(descendants.map((leaf) => leaf.nodeBox)) ?? parentBox;\n return {\n id,\n ancestors: new Set(ancestorIds),\n descendants,\n insets: {\n left: Math.max(0, descendantUnion.x1 - parentBox.x1),\n right: Math.max(0, parentBox.x2 - descendantUnion.x2),\n top: Math.max(0, descendantUnion.y1 - parentBox.y1),\n bottom: Math.max(0, parentBox.y2 - descendantUnion.y2),\n },\n };\n}\n\n/*** Resolve immutable label and compound boxes for one candidate uniform spacing factor. */\nfunction resolveCollisionBoxes(\n leaves: readonly LeafGeometry[],\n groups: readonly GroupGeometry[],\n center: Point,\n factor: number,\n): readonly CollisionBox[] {\n const labels = leaves.map((leaf) => ({\n id: leaf.id,\n ancestors: leaf.ancestors,\n kind: 'label' as const,\n box: shiftBounds(leaf.labelBox, leaf.position, center, factor),\n }));\n const compoundBoxes = groups.flatMap((group) => {\n const descendants = group.descendants.map((leaf) =>\n shiftBounds(leaf.nodeBox, leaf.position, center, factor),\n );\n const union = unionBounds(descendants);\n if (!union) return [];\n return [\n {\n id: group.id,\n ancestors: group.ancestors,\n kind: 'group' as const,\n box: expandBounds(union, group.insets),\n },\n ];\n });\n return [...labels, ...compoundBoxes];\n}\n\n/*** Find the first bounded expansion factor that makes the pure geometry snapshot acceptable. */\nfunction findExpansionMaximum(accepts: (factor: number) => boolean): number | undefined {\n return Array.from({ length: MAX_EXPANSION_ATTEMPTS }, (_, index) => 2 ** (index + 1)).find(\n accepts,\n );\n}\n\n/***\n * Sweep resolved boxes by x extent and stop conservatively if the pair-check budget is exhausted.\n * Local loop counters are intentionally mutable on this performance-critical boundary.\n */\nfunction hasUnsafeCollisions(boxes: readonly CollisionBox[]): boolean {\n const sorted = [...boxes].sort((first, second) => first.box.x1 - second.box.x1);\n const budget = { remaining: MAX_PAIR_CHECKS };\n for (const [index, first] of sorted.entries()) {\n for (let next = index + 1; next < sorted.length; next += 1) {\n const second = sorted.at(next);\n if (!second) break;\n if (second.box.x1 >= first.box.x2) break;\n budget.remaining -= 1;\n if (budget.remaining < 0) return true;\n if (isIntentionalContainment(first, second)) continue;\n if (isUnsafeOverlap(first, second)) return true;\n }\n }\n return false;\n}\n\n/*** Ignore intentional compound containment while retaining sibling and unrelated separation. */\nfunction isIntentionalContainment(first: CollisionBox, second: CollisionBox): boolean {\n return first.ancestors.has(second.id) || second.ancestors.has(first.id);\n}\n\n/*** Permit only a small bounded label-label overlap; every other intersection remains unsafe. */\nfunction isUnsafeOverlap(first: CollisionBox, second: CollisionBox): boolean {\n const overlapWidth =\n Math.min(first.box.x2, second.box.x2) - Math.max(first.box.x1, second.box.x1);\n const overlapHeight =\n Math.min(first.box.y2, second.box.y2) - Math.max(first.box.y1, second.box.y1);\n if (overlapWidth <= 0 || overlapHeight <= 0) return false;\n if (first.kind !== 'label' || second.kind !== 'label') return true;\n const widthRatio = overlapWidth / Math.min(first.box.w, second.box.w);\n const heightRatio = overlapHeight / Math.min(first.box.h, second.box.h);\n return widthRatio > LABEL_OVERLAP_RATIO && heightRatio > LABEL_OVERLAP_RATIO;\n}\n\n/*** Shift one fixed renderer box with its leaf center under uniform radial scaling. */\nfunction shiftBounds(box: Bounds, position: Point, center: Point, factor: number): Bounds {\n const dx = (position.x - center.x) * (factor - 1);\n const dy = (position.y - center.y) * (factor - 1);\n return {\n x1: box.x1 + dx,\n y1: box.y1 + dy,\n x2: box.x2 + dx,\n y2: box.y2 + dy,\n w: box.w,\n h: box.h,\n };\n}\n\n/*** Expand a descendant union by the compound renderer's measured outer insets. */\nfunction expandBounds(box: Bounds, insets: Insets): Bounds {\n const x1 = box.x1 - insets.left;\n const y1 = box.y1 - insets.top;\n const x2 = box.x2 + insets.right;\n const y2 = box.y2 + insets.bottom;\n return { x1, y1, x2, y2, w: x2 - x1, h: y2 - y1 };\n}\n\n/*** Return the immutable union of measured boxes, or undefined for an empty collection. */\nfunction unionBounds(boxes: readonly Bounds[]): Bounds | undefined {\n if (boxes.length === 0) return undefined;\n const x1 = Math.min(...boxes.map((box) => box.x1));\n const y1 = Math.min(...boxes.map((box) => box.y1));\n const x2 = Math.max(...boxes.map((box) => box.x2));\n const y2 = Math.max(...boxes.map((box) => box.y2));\n return { x1, y1, x2, y2, w: x2 - x1, h: y2 - y1 };\n}\n\n/*** Return whether renderer measurement produced a non-empty label box. */\nfunction isUsableBox(box: Bounds): boolean {\n return box.w > 0 && box.h > 0;\n}\n\n/*** Apply the accepted factor once, preserving node dimensions, hierarchy, ordering and edge data. */\nfunction applyScale(\n cy: Core,\n leaves: readonly LeafGeometry[],\n center: Point,\n factor: number,\n): void {\n const positions = new Map(leaves.map((leaf) => [leaf.id, leaf.position]));\n cy.batch(() => {\n cy.nodes()\n .not(':parent')\n .positions((node) => {\n const original = positions.get(node.id()) ?? node.position();\n return {\n x: center.x + (original.x - center.x) * factor,\n y: center.y + (original.y - center.y) * factor,\n };\n });\n });\n}\n"]}
1
+ {"version":3,"file":"compactGraphSpacing.js","sourceRoot":"","sources":["../../../../../../src/features/graph-view/adapters/inbound/web-artifact/compactGraphSpacing.ts"],"names":[],"mappings":"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","sourcesContent":["import { findMinimumAcceptedNumber } from '@ankhorage/utility/algorithms';\nimport type { Core, NodeSingular } from 'cytoscape';\n\nconst LABEL_OVERLAP_RATIO = 0.12;\nconst MAX_EXPANSION_ATTEMPTS = 8;\nconst MAX_NODE_COUNT = 2000;\nconst MAX_PAIR_CHECKS = 200000;\nconst SEARCH_ITERATIONS = 8;\n\n/***\n * Optimize settled layout spacing around readable label bounds instead of full node clearance.\n * Compound containment stays intentional while sibling groups retain non-overlapping boundaries.\n * Cytoscape geometry is measured once, then bounded pure numeric trials reuse the\n * immutable snapshot. No layout reruns, zoom work, or intermediate frames are painted.\n */\nexport function compactGraphSpacing(cy: Core, spacingFactor: number): number {\n const leaves = cy.nodes(':childless');\n if (leaves.length < 2 || cy.nodes().length > MAX_NODE_COUNT || cy.nodes(':locked').length > 0)\n return spacingFactor;\n\n const bounds = leaves.boundingBox();\n const center = { x: (bounds.x1 + bounds.x2) / 2, y: (bounds.y1 + bounds.y2) / 2 };\n const leafGeometry = leaves.map(readLeafGeometry);\n const groups = cy.nodes(':parent').map((node) =>\n readGroupGeometry(\n node.id(),\n node.ancestors().map((parent) => parent.id()),\n node.boundingBox(),\n leafGeometry,\n ),\n );\n const accepts = (factor: number) =>\n !hasUnsafeCollisions(resolveCollisionBoxes(leafGeometry, groups, center, factor));\n const currentAccepted = accepts(1);\n const minimum = currentAccepted ? Math.min(1, 0.1 / spacingFactor) : 1;\n const maximum = currentAccepted ? 1 : findExpansionMaximum(accepts);\n if (maximum === undefined) return spacingFactor;\n\n const factor = findMinimumAcceptedNumber({\n minimum,\n maximum,\n iterations: SEARCH_ITERATIONS,\n accepts,\n });\n if (factor === undefined) return spacingFactor;\n\n applyScale(cy, leafGeometry, center, factor);\n return spacingFactor * factor;\n}\n\ninterface Point {\n readonly x: number;\n readonly y: number;\n}\n\ninterface Bounds {\n readonly x1: number;\n readonly y1: number;\n readonly x2: number;\n readonly y2: number;\n readonly w: number;\n readonly h: number;\n}\n\ninterface Insets {\n readonly left: number;\n readonly right: number;\n readonly top: number;\n readonly bottom: number;\n}\n\ninterface LeafGeometry {\n readonly id: string;\n readonly ancestors: ReadonlySet<string>;\n readonly position: Point;\n readonly labelBox: Bounds;\n readonly nodeBox: Bounds;\n}\n\ninterface GroupGeometry {\n readonly id: string;\n readonly ancestors: ReadonlySet<string>;\n readonly descendants: readonly LeafGeometry[];\n readonly insets: Insets;\n}\n\ninterface CollisionBox {\n readonly id: string;\n readonly ancestors: ReadonlySet<string>;\n readonly kind: 'label' | 'group';\n readonly box: Bounds;\n}\n\n/*** Read one leaf's immutable position, hierarchy and renderer-measured label geometry. */\nfunction readLeafGeometry(node: NodeSingular): LeafGeometry {\n const nodeBox = node.boundingBox({\n includeLabels: true,\n includeOverlays: false,\n includeUnderlays: false,\n });\n const labelBox = node.boundingBox({\n includeNodes: false,\n includeEdges: false,\n includeLabels: true,\n includeOverlays: false,\n includeUnderlays: false,\n });\n return {\n id: node.id(),\n ancestors: new Set(node.ancestors().map((parent) => parent.id())),\n position: { ...node.position() },\n labelBox: isUsableBox(labelBox) ? labelBox : nodeBox,\n nodeBox,\n };\n}\n\n/*** Capture one compound group's descendant geometry and constant renderer-owned outer insets. */\nfunction readGroupGeometry(\n id: string,\n ancestorIds: readonly string[],\n parentBox: Bounds,\n leaves: readonly LeafGeometry[],\n): GroupGeometry {\n const descendants = leaves.filter((leaf) => leaf.ancestors.has(id));\n const descendantUnion = unionBounds(descendants.map((leaf) => leaf.nodeBox)) ?? parentBox;\n return {\n id,\n ancestors: new Set(ancestorIds),\n descendants,\n insets: {\n left: Math.max(0, descendantUnion.x1 - parentBox.x1),\n right: Math.max(0, parentBox.x2 - descendantUnion.x2),\n top: Math.max(0, descendantUnion.y1 - parentBox.y1),\n bottom: Math.max(0, parentBox.y2 - descendantUnion.y2),\n },\n };\n}\n\n/*** Resolve immutable label and compound boxes for one candidate uniform spacing factor. */\nfunction resolveCollisionBoxes(\n leaves: readonly LeafGeometry[],\n groups: readonly GroupGeometry[],\n center: Point,\n factor: number,\n): readonly CollisionBox[] {\n const labels = leaves.map((leaf) => ({\n id: leaf.id,\n ancestors: leaf.ancestors,\n kind: 'label' as const,\n box: shiftBounds(leaf.labelBox, leaf.position, center, factor),\n }));\n const compoundBoxes = groups.flatMap((group) => {\n const descendants = group.descendants.map((leaf) =>\n shiftBounds(leaf.nodeBox, leaf.position, center, factor),\n );\n const union = unionBounds(descendants);\n if (!union) return [];\n return [\n {\n id: group.id,\n ancestors: group.ancestors,\n kind: 'group' as const,\n box: expandBounds(union, group.insets),\n },\n ];\n });\n return [...labels, ...compoundBoxes];\n}\n\n/*** Find the first bounded expansion factor that makes the pure geometry snapshot acceptable. */\nfunction findExpansionMaximum(accepts: (factor: number) => boolean): number | undefined {\n return Array.from({ length: MAX_EXPANSION_ATTEMPTS }, (_, index) => 2 ** (index + 1)).find(\n accepts,\n );\n}\n\n/***\n * Sweep resolved boxes by x extent and stop conservatively if the pair-check budget is exhausted.\n * Local loop counters are intentionally mutable on this performance-critical boundary.\n */\nfunction hasUnsafeCollisions(boxes: readonly CollisionBox[]): boolean {\n const sorted = [...boxes].sort((first, second) => first.box.x1 - second.box.x1);\n const budget = { remaining: MAX_PAIR_CHECKS };\n for (const [index, first] of sorted.entries()) {\n for (let next = index + 1; next < sorted.length; next += 1) {\n const second = sorted.at(next);\n if (!second) break;\n if (second.box.x1 >= first.box.x2) break;\n budget.remaining -= 1;\n if (budget.remaining < 0) return true;\n if (isIntentionalContainment(first, second)) continue;\n if (isUnsafeOverlap(first, second)) return true;\n }\n }\n return false;\n}\n\n/*** Ignore intentional compound containment while retaining sibling and unrelated separation. */\nfunction isIntentionalContainment(first: CollisionBox, second: CollisionBox): boolean {\n return first.ancestors.has(second.id) || second.ancestors.has(first.id);\n}\n\n/*** Permit only a small bounded label-label overlap; every other intersection remains unsafe. */\nfunction isUnsafeOverlap(first: CollisionBox, second: CollisionBox): boolean {\n const overlapWidth =\n Math.min(first.box.x2, second.box.x2) - Math.max(first.box.x1, second.box.x1);\n const overlapHeight =\n Math.min(first.box.y2, second.box.y2) - Math.max(first.box.y1, second.box.y1);\n if (overlapWidth <= 0 || overlapHeight <= 0) return false;\n if (first.kind !== 'label' || second.kind !== 'label') return true;\n const widthRatio = overlapWidth / Math.min(first.box.w, second.box.w);\n const heightRatio = overlapHeight / Math.min(first.box.h, second.box.h);\n return widthRatio > LABEL_OVERLAP_RATIO && heightRatio > LABEL_OVERLAP_RATIO;\n}\n\n/*** Shift one fixed renderer box with its leaf center under uniform radial scaling. */\nfunction shiftBounds(box: Bounds, position: Point, center: Point, factor: number): Bounds {\n const dx = (position.x - center.x) * (factor - 1);\n const dy = (position.y - center.y) * (factor - 1);\n return {\n x1: box.x1 + dx,\n y1: box.y1 + dy,\n x2: box.x2 + dx,\n y2: box.y2 + dy,\n w: box.w,\n h: box.h,\n };\n}\n\n/*** Expand a descendant union by the compound renderer's measured outer insets. */\nfunction expandBounds(box: Bounds, insets: Insets): Bounds {\n const x1 = box.x1 - insets.left;\n const y1 = box.y1 - insets.top;\n const x2 = box.x2 + insets.right;\n const y2 = box.y2 + insets.bottom;\n return { x1, y1, x2, y2, w: x2 - x1, h: y2 - y1 };\n}\n\n/*** Return the immutable union of measured boxes, or undefined for an empty collection. */\nfunction unionBounds(boxes: readonly Bounds[]): Bounds | undefined {\n if (boxes.length === 0) return undefined;\n const x1 = Math.min(...boxes.map((box) => box.x1));\n const y1 = Math.min(...boxes.map((box) => box.y1));\n const x2 = Math.max(...boxes.map((box) => box.x2));\n const y2 = Math.max(...boxes.map((box) => box.y2));\n return { x1, y1, x2, y2, w: x2 - x1, h: y2 - y1 };\n}\n\n/*** Return whether renderer measurement produced a non-empty label box. */\nfunction isUsableBox(box: Bounds): boolean {\n return box.w > 0 && box.h > 0;\n}\n\n/*** Apply the accepted factor once, preserving node dimensions, hierarchy, ordering and edge data. */\nfunction applyScale(\n cy: Core,\n leaves: readonly LeafGeometry[],\n center: Point,\n factor: number,\n): void {\n const positions = new Map(leaves.map((leaf) => [leaf.id, leaf.position]));\n cy.batch(() => {\n cy.nodes()\n .not(':parent')\n .positions((node) => {\n const original = positions.get(node.id()) ?? node.position();\n return {\n x: center.x + (original.x - center.x) * factor,\n y: center.y + (original.y - center.y) * factor,\n };\n });\n });\n}\n"]}
@@ -89,7 +89,7 @@ function positiveSize(value, fallback) {
89
89
  }
90
90
  /***
91
91
  * Recompute the fit reference only after layout or resize, never on every pan/zoom event.
92
- * @performance Cache the geometry-derived scale in the viewport owner; labels are included, edges excluded.
92
+ * Cache the geometry-derived scale in the viewport owner; labels are included, edges excluded.
93
93
  */
94
94
  function getNodeFitZoom(cy, padding) {
95
95
  if (cy.nodes().empty())
@@ -1 +1 @@
1
- {"version":3,"file":"createGraphController.js","sourceRoot":"","sources":["../../../../../../src/features/graph-view/adapters/inbound/web-artifact/createGraphController.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Core } from 'cytoscape';\n\nimport type { GraphRuntimeUpdate } from '../../../../../types/graphViewRuntime';\nimport { fitGraphViewport } from './fitGraphViewport';\nimport type { GraphViewController, GraphViewFitOptions } from './GraphView';\n\n/*** Own viewport units and limits alongside the public controller, without exposing Cytoscape. */\nexport function createGraphController(\n cy: Core,\n fitPaddingRef: { current: number },\n optimizeFit?: (options: GraphViewFitOptions) => void,\n) {\n const state = {\n scale: 1,\n relative: false,\n min: 0.05,\n max: 2,\n readableSize: 0,\n fitSize: Infinity,\n readableZoom: 0,\n fitZoom: Infinity,\n };\n const controller: GraphViewController = {\n fit(options) {\n if (options?.optimizeSpacing && !options.nodeIds?.length && optimizeFit) {\n optimizeFit(options);\n return;\n }\n fitGraphViewport(\n cy,\n {\n nodeIds: options?.nodeIds,\n padding: options?.padding ?? fitPaddingRef.current,\n },\n state.fitZoom,\n );\n },\n getViewport() {\n return { pan: cy.pan(), zoom: cy.zoom() / state.scale };\n },\n getZoomRange() {\n return { min: cy.minZoom() / state.scale, max: cy.maxZoom() / state.scale };\n },\n setPan(pan) {\n cy.pan(pan);\n },\n setZoom(zoom) {\n setCenteredZoom(cy, zoom * state.scale);\n },\n zoomBy(factor) {\n setCenteredZoom(cy, cy.zoom() * factor);\n },\n };\n\n return {\n controller,\n configure(input: GraphRuntimeUpdate) {\n state.relative = input.zoomMode === 'fit-relative';\n state.min = input.minZoom ?? 0.05;\n state.max = input.maxZoom ?? 2;\n state.readableSize = positiveSize(input.minReadableLabelSize, 0);\n state.fitSize = positiveSize(input.maxFitLabelSize, Infinity);\n if (!state.relative) state.scale = 1;\n applyZoomLimits(cy, state);\n },\n settle(fit: boolean) {\n const logicalZoom = cy.zoom() / state.scale;\n const fonts = cy\n .nodes()\n .filter((node) => !node.isParent() && Boolean(node.style('label')))\n .map((node) => Number.parseFloat(String(node.style('font-size'))))\n .filter((size) => Number.isFinite(size) && size > 0);\n state.readableZoom = fonts.length\n ? state.readableSize / fonts.reduce((minimum, size) => Math.min(minimum, size), Infinity)\n : 0;\n state.fitZoom = fonts.length\n ? state.fitSize / fonts.reduce((maximum, size) => Math.max(maximum, size), 0)\n : Infinity;\n state.scale = state.relative\n ? Math.min(getNodeFitZoom(cy, fitPaddingRef.current), state.fitZoom)\n : 1;\n applyZoomLimits(cy, state);\n if (fit) controller.fit();\n else if (state.relative) {\n setCenteredZoom(cy, logicalZoom * state.scale);\n cy.center(cy.nodes());\n }\n },\n };\n}\n\n/*** Keep pointer, wheel, and programmatic zoom on the same limits in the engine's native units. */\nfunction applyZoomLimits(\n cy: Core,\n state: {\n readonly min: number;\n readonly max: number;\n readonly scale: number;\n readonly readableZoom: number;\n },\n) {\n const min = state.min * state.scale;\n cy.minZoom(Math.min(cy.minZoom(), min));\n cy.maxZoom(Math.max(min, state.max * state.scale, state.readableZoom));\n cy.minZoom(min);\n}\n\n/*** Ignore invalid optional typography targets at the public configuration boundary. */\nfunction positiveSize(value: number | undefined, fallback: number): number {\n return value !== undefined && Number.isFinite(value) && value > 0 ? value : fallback;\n}\n\n/***\n * Recompute the fit reference only after layout or resize, never on every pan/zoom event.\n * @performance Cache the geometry-derived scale in the viewport owner; labels are included, edges excluded.\n */\nfunction getNodeFitZoom(cy: Core, padding: number): number {\n if (cy.nodes().empty()) return 1;\n const bounds = cy.nodes().boundingBox();\n const width = cy.width() - 2 * padding;\n const height = cy.height() - 2 * padding;\n if (width <= 0 || height <= 0 || bounds.w <= 0 || bounds.h <= 0) return 1;\n return Math.min(width / bounds.w, height / bounds.h);\n}\n\n/*** Zoom around the visible viewport center instead of its top-left corner. */\nfunction setCenteredZoom(cy: Core, zoom: number) {\n cy.zoom({ level: zoom, renderedPosition: { x: cy.width() / 2, y: cy.height() / 2 } });\n}\n"]}
1
+ {"version":3,"file":"createGraphController.js","sourceRoot":"","sources":["../../../../../../src/features/graph-view/adapters/inbound/web-artifact/createGraphController.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Core } from 'cytoscape';\n\nimport type { GraphRuntimeUpdate } from '../../../../../types/graphViewRuntime';\nimport { fitGraphViewport } from './fitGraphViewport';\nimport type { GraphViewController, GraphViewFitOptions } from './GraphView';\n\n/*** Own viewport units and limits alongside the public controller, without exposing Cytoscape. */\nexport function createGraphController(\n cy: Core,\n fitPaddingRef: { current: number },\n optimizeFit?: (options: GraphViewFitOptions) => void,\n) {\n const state = {\n scale: 1,\n relative: false,\n min: 0.05,\n max: 2,\n readableSize: 0,\n fitSize: Infinity,\n readableZoom: 0,\n fitZoom: Infinity,\n };\n const controller: GraphViewController = {\n fit(options) {\n if (options?.optimizeSpacing && !options.nodeIds?.length && optimizeFit) {\n optimizeFit(options);\n return;\n }\n fitGraphViewport(\n cy,\n {\n nodeIds: options?.nodeIds,\n padding: options?.padding ?? fitPaddingRef.current,\n },\n state.fitZoom,\n );\n },\n getViewport() {\n return { pan: cy.pan(), zoom: cy.zoom() / state.scale };\n },\n getZoomRange() {\n return { min: cy.minZoom() / state.scale, max: cy.maxZoom() / state.scale };\n },\n setPan(pan) {\n cy.pan(pan);\n },\n setZoom(zoom) {\n setCenteredZoom(cy, zoom * state.scale);\n },\n zoomBy(factor) {\n setCenteredZoom(cy, cy.zoom() * factor);\n },\n };\n\n return {\n controller,\n configure(input: GraphRuntimeUpdate) {\n state.relative = input.zoomMode === 'fit-relative';\n state.min = input.minZoom ?? 0.05;\n state.max = input.maxZoom ?? 2;\n state.readableSize = positiveSize(input.minReadableLabelSize, 0);\n state.fitSize = positiveSize(input.maxFitLabelSize, Infinity);\n if (!state.relative) state.scale = 1;\n applyZoomLimits(cy, state);\n },\n settle(fit: boolean) {\n const logicalZoom = cy.zoom() / state.scale;\n const fonts = cy\n .nodes()\n .filter((node) => !node.isParent() && Boolean(node.style('label')))\n .map((node) => Number.parseFloat(String(node.style('font-size'))))\n .filter((size) => Number.isFinite(size) && size > 0);\n state.readableZoom = fonts.length\n ? state.readableSize / fonts.reduce((minimum, size) => Math.min(minimum, size), Infinity)\n : 0;\n state.fitZoom = fonts.length\n ? state.fitSize / fonts.reduce((maximum, size) => Math.max(maximum, size), 0)\n : Infinity;\n state.scale = state.relative\n ? Math.min(getNodeFitZoom(cy, fitPaddingRef.current), state.fitZoom)\n : 1;\n applyZoomLimits(cy, state);\n if (fit) controller.fit();\n else if (state.relative) {\n setCenteredZoom(cy, logicalZoom * state.scale);\n cy.center(cy.nodes());\n }\n },\n };\n}\n\n/*** Keep pointer, wheel, and programmatic zoom on the same limits in the engine's native units. */\nfunction applyZoomLimits(\n cy: Core,\n state: {\n readonly min: number;\n readonly max: number;\n readonly scale: number;\n readonly readableZoom: number;\n },\n) {\n const min = state.min * state.scale;\n cy.minZoom(Math.min(cy.minZoom(), min));\n cy.maxZoom(Math.max(min, state.max * state.scale, state.readableZoom));\n cy.minZoom(min);\n}\n\n/*** Ignore invalid optional typography targets at the public configuration boundary. */\nfunction positiveSize(value: number | undefined, fallback: number): number {\n return value !== undefined && Number.isFinite(value) && value > 0 ? value : fallback;\n}\n\n/***\n * Recompute the fit reference only after layout or resize, never on every pan/zoom event.\n * Cache the geometry-derived scale in the viewport owner; labels are included, edges excluded.\n */\nfunction getNodeFitZoom(cy: Core, padding: number): number {\n if (cy.nodes().empty()) return 1;\n const bounds = cy.nodes().boundingBox();\n const width = cy.width() - 2 * padding;\n const height = cy.height() - 2 * padding;\n if (width <= 0 || height <= 0 || bounds.w <= 0 || bounds.h <= 0) return 1;\n return Math.min(width / bounds.w, height / bounds.h);\n}\n\n/*** Zoom around the visible viewport center instead of its top-left corner. */\nfunction setCenteredZoom(cy: Core, zoom: number) {\n cy.zoom({ level: zoom, renderedPosition: { x: cy.width() / 2, y: cy.height() / 2 } });\n}\n"]}
@@ -1,7 +1,7 @@
1
1
  import type { Core } from 'cytoscape';
2
2
  /***
3
3
  * Keeps self-loop control points outside the rendered node, independent of label size and direction.
4
- * @performance Reconcile loop geometry only after size/style/layout changes, never on pan or zoom.
4
+ * Reconcile loop geometry only after size/style/layout changes, never on pan or zoom.
5
5
  * Preserve valid dependencies and configured larger loops; do not hide edges or silence warnings.
6
6
  */
7
7
  export declare function createGraphLoopSizer(cy: Core): {
@@ -1,6 +1,6 @@
1
1
  /***
2
2
  * Keeps self-loop control points outside the rendered node, independent of label size and direction.
3
- * @performance Reconcile loop geometry only after size/style/layout changes, never on pan or zoom.
3
+ * Reconcile loop geometry only after size/style/layout changes, never on pan or zoom.
4
4
  * Preserve valid dependencies and configured larger loops; do not hide edges or silence warnings.
5
5
  */
6
6
  export function createGraphLoopSizer(cy) {
@@ -1 +1 @@
1
- {"version":3,"file":"createGraphLoopSizer.js","sourceRoot":"","sources":["../../../../../../src/features/graph-view/adapters/inbound/web-artifact/createGraphLoopSizer.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Core } from 'cytoscape';\n\n/***\n * Keeps self-loop control points outside the rendered node, independent of label size and direction.\n * @performance Reconcile loop geometry only after size/style/layout changes, never on pan or zoom.\n * Preserve valid dependencies and configured larger loops; do not hide edges or silence warnings.\n */\nexport function createGraphLoopSizer(cy: Core) {\n const configured = new Map<string, { step: number; distance: number }>();\n\n /*** Releases only this owner's overrides before a new stylesheet is applied. */\n function reset() {\n for (const id of configured.keys()) {\n cy.getElementById(id).removeStyle('control-point-step-size control-point-distances');\n }\n configured.clear();\n }\n\n /*** Reconciles loop clearances, including compound bounds after layout completion. */\n function update() {\n const loops = cy.edges(':loop');\n const active = new Set(loops.map((edge) => edge.id()));\n for (const id of configured.keys()) {\n if (active.has(id)) continue;\n cy.getElementById(id).removeStyle('control-point-step-size control-point-distances');\n configured.delete(id);\n }\n cy.batch(() => {\n loops.forEach((edge) => {\n const node = edge.source();\n const original = configured.get(edge.id()) ?? {\n step: Number.parseFloat(String(edge.style('control-point-step-size'))) || 40,\n distance: Number.parseFloat(String(edge.style('control-point-distances'))) || 40,\n };\n configured.set(edge.id(), original);\n const clearance = Math.max(\n 16,\n edge.width() * Number.parseFloat(String(edge.style('arrow-scale'))) * 2,\n );\n const minimum = (Math.hypot(node.outerWidth(), node.outerHeight()) / 2 + clearance) / 1.4;\n const step = Math.max(original.step, minimum);\n const distance = Math.max(original.distance, minimum);\n if (Number.parseFloat(String(edge.style('control-point-step-size'))) !== step)\n edge.style('control-point-step-size', step);\n if (Number.parseFloat(String(edge.style('control-point-distances'))) !== distance)\n edge.style('control-point-distances', distance);\n });\n });\n }\n\n return { reset, update };\n}\n"]}
1
+ {"version":3,"file":"createGraphLoopSizer.js","sourceRoot":"","sources":["../../../../../../src/features/graph-view/adapters/inbound/web-artifact/createGraphLoopSizer.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Core } from 'cytoscape';\n\n/***\n * Keeps self-loop control points outside the rendered node, independent of label size and direction.\n * Reconcile loop geometry only after size/style/layout changes, never on pan or zoom.\n * Preserve valid dependencies and configured larger loops; do not hide edges or silence warnings.\n */\nexport function createGraphLoopSizer(cy: Core) {\n const configured = new Map<string, { step: number; distance: number }>();\n\n /*** Releases only this owner's overrides before a new stylesheet is applied. */\n function reset() {\n for (const id of configured.keys()) {\n cy.getElementById(id).removeStyle('control-point-step-size control-point-distances');\n }\n configured.clear();\n }\n\n /*** Reconciles loop clearances, including compound bounds after layout completion. */\n function update() {\n const loops = cy.edges(':loop');\n const active = new Set(loops.map((edge) => edge.id()));\n for (const id of configured.keys()) {\n if (active.has(id)) continue;\n cy.getElementById(id).removeStyle('control-point-step-size control-point-distances');\n configured.delete(id);\n }\n cy.batch(() => {\n loops.forEach((edge) => {\n const node = edge.source();\n const original = configured.get(edge.id()) ?? {\n step: Number.parseFloat(String(edge.style('control-point-step-size'))) || 40,\n distance: Number.parseFloat(String(edge.style('control-point-distances'))) || 40,\n };\n configured.set(edge.id(), original);\n const clearance = Math.max(\n 16,\n edge.width() * Number.parseFloat(String(edge.style('arrow-scale'))) * 2,\n );\n const minimum = (Math.hypot(node.outerWidth(), node.outerHeight()) / 2 + clearance) / 1.4;\n const step = Math.max(original.step, minimum);\n const distance = Math.max(original.distance, minimum);\n if (Number.parseFloat(String(edge.style('control-point-step-size'))) !== step)\n edge.style('control-point-step-size', step);\n if (Number.parseFloat(String(edge.style('control-point-distances'))) !== distance)\n edge.style('control-point-distances', distance);\n });\n });\n }\n\n return { reset, update };\n}\n"]}