@weasel-js/core 1.11.0 → 1.12.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 (586) hide show
  1. package/CHANGELOG.md +611 -0
  2. package/README.md +1 -1
  3. package/dist/WeaselProvider.js +1 -1
  4. package/dist/affordances/pathAnchors.js +10 -6
  5. package/dist/affordances/pathAnchors.js.map +1 -1
  6. package/dist/animation/index.js +3 -3
  7. package/dist/animation/rig/bindRig.js +1 -1
  8. package/dist/animation/rig/rigNode.js.map +1 -1
  9. package/dist/barrel/canvas.js +9 -3
  10. package/dist/barrel/interactions.js +5 -4
  11. package/dist/barrel/paint.js +4 -4
  12. package/dist/barrel/paths.js +10 -6
  13. package/dist/barrel/renderer.js +5 -3
  14. package/dist/barrel/routing.js +7 -12
  15. package/dist/barrel/scene.js +9 -5
  16. package/dist/barrel/text.js +2 -2
  17. package/dist/barrel/viewport.js +9 -4
  18. package/dist/canvas/Canvas.js +5 -2
  19. package/dist/canvas/Canvas.js.map +1 -1
  20. package/dist/canvas/CanvasView.js +23 -34
  21. package/dist/canvas/CanvasView.js.map +1 -1
  22. package/dist/canvas/ModalityHud.js +1 -1
  23. package/dist/canvas/NodeShape.js +4 -1
  24. package/dist/canvas/NodeShape.js.map +1 -1
  25. package/dist/canvas/SceneCanvas/ActionsProviderIfRoot.js +1 -1
  26. package/dist/canvas/SceneCanvas/DepRegistryProviderIfRoot.js +1 -1
  27. package/dist/canvas/SceneCanvas/PointerProviderIfRoot.js +1 -1
  28. package/dist/canvas/SceneCanvas/SceneCanvasInput.js +17 -3
  29. package/dist/canvas/SceneCanvas/SceneCanvasInput.js.map +1 -1
  30. package/dist/canvas/SceneCanvas/SurfaceDeclarations.js +23 -0
  31. package/dist/canvas/SceneCanvas/SurfaceDeclarations.js.map +1 -0
  32. package/dist/canvas/SceneCanvas/builtinToolSets.js +30 -0
  33. package/dist/canvas/SceneCanvas/builtinToolSets.js.map +1 -0
  34. package/dist/canvas/SceneCanvas/canvasPassThrough.js +2 -0
  35. package/dist/canvas/SceneCanvas/canvasPassThrough.js.map +1 -1
  36. package/dist/canvas/SceneCanvas/coordTrace.js +5 -16
  37. package/dist/canvas/SceneCanvas/coordTrace.js.map +1 -1
  38. package/dist/canvas/SceneCanvas/defaultNodeProperties.js +5 -0
  39. package/dist/canvas/SceneCanvas/defaultNodeProperties.js.map +1 -1
  40. package/dist/canvas/SceneCanvas/features.js +45 -5
  41. package/dist/canvas/SceneCanvas/features.js.map +1 -1
  42. package/dist/canvas/SceneCanvas/props.js +1 -11
  43. package/dist/canvas/SceneCanvas/props.js.map +1 -1
  44. package/dist/canvas/SceneCanvas/scenePointQuery.js +7 -3
  45. package/dist/canvas/SceneCanvas/scenePointQuery.js.map +1 -1
  46. package/dist/canvas/SceneCanvas/toolRegistry.js +8 -4
  47. package/dist/canvas/SceneCanvas/toolRegistry.js.map +1 -1
  48. package/dist/canvas/SceneCanvas/useActionTunings.js +6 -1
  49. package/dist/canvas/SceneCanvas/useActionTunings.js.map +1 -1
  50. package/dist/canvas/SceneCanvas/useActionsPropResolver.js +1 -11
  51. package/dist/canvas/SceneCanvas/useActionsPropResolver.js.map +1 -1
  52. package/dist/canvas/SceneCanvas/useBuiltinShapeTools.js.map +1 -1
  53. package/dist/canvas/SceneCanvas/useBuiltinTools.js +2 -9
  54. package/dist/canvas/SceneCanvas/useBuiltinTools.js.map +1 -1
  55. package/dist/canvas/SceneCanvas/useCanvasDevtoolsRoot.js +94 -0
  56. package/dist/canvas/SceneCanvas/useCanvasDevtoolsRoot.js.map +1 -0
  57. package/dist/canvas/SceneCanvas/useCanvasSelection.js +7 -2
  58. package/dist/canvas/SceneCanvas/useCanvasSelection.js.map +1 -1
  59. package/dist/canvas/SceneCanvas/useCanvasTools.js +15 -10
  60. package/dist/canvas/SceneCanvas/useCanvasTools.js.map +1 -1
  61. package/dist/canvas/SceneCanvas/useNodeKinds.js +1 -1
  62. package/dist/canvas/SceneCanvas/useNodeKinds.js.map +1 -1
  63. package/dist/canvas/SceneCanvas/useSceneCanvasHandle.js +9 -3
  64. package/dist/canvas/SceneCanvas/useSceneCanvasHandle.js.map +1 -1
  65. package/dist/canvas/SceneCanvas/useSceneCanvasLayers.js +23 -4
  66. package/dist/canvas/SceneCanvas/useSceneCanvasLayers.js.map +1 -1
  67. package/dist/canvas/SceneCanvas/useSceneCanvasTools.js +2 -3
  68. package/dist/canvas/SceneCanvas/useSceneCanvasTools.js.map +1 -1
  69. package/dist/canvas/SceneCanvas/useSceneChrome.js +6 -7
  70. package/dist/canvas/SceneCanvas/useSceneChrome.js.map +1 -1
  71. package/dist/canvas/SceneCanvas/useSceneGestureDispatcher.js +24 -7
  72. package/dist/canvas/SceneCanvas/useSceneGestureDispatcher.js.map +1 -1
  73. package/dist/canvas/SceneCanvas/useScenePicking.js +2 -3
  74. package/dist/canvas/SceneCanvas/useScenePicking.js.map +1 -1
  75. package/dist/canvas/SceneCanvas/useSceneSelectTool.js +2 -1
  76. package/dist/canvas/SceneCanvas/useSceneSelectTool.js.map +1 -1
  77. package/dist/canvas/SceneCanvas/useSceneStandardActions.js +5 -5
  78. package/dist/canvas/SceneCanvas/useSceneStandardActions.js.map +1 -1
  79. package/dist/canvas/SceneCanvas.js +27 -24
  80. package/dist/canvas/SceneCanvas.js.map +1 -1
  81. package/dist/canvas/SurfaceCanvas.js +5 -22
  82. package/dist/canvas/SurfaceCanvas.js.map +1 -1
  83. package/dist/canvas/ViewMarker.js +35 -0
  84. package/dist/canvas/ViewMarker.js.map +1 -0
  85. package/dist/canvas/canvasRenderer.js +9 -5
  86. package/dist/canvas/canvasRenderer.js.map +1 -1
  87. package/dist/canvas/contextAttributes.js +14 -0
  88. package/dist/canvas/contextAttributes.js.map +1 -0
  89. package/dist/canvas/defaultDrawOne.js +2 -0
  90. package/dist/canvas/defaultDrawOne.js.map +1 -1
  91. package/dist/canvas/deps/booleans.js +2 -1
  92. package/dist/canvas/deps/booleans.js.map +1 -1
  93. package/dist/canvas/deps/editAnchors.js +9 -113
  94. package/dist/canvas/deps/editAnchors.js.map +1 -1
  95. package/dist/canvas/deps/hitTestArea.js +2 -2
  96. package/dist/canvas/deps/hitTestArea.js.map +1 -1
  97. package/dist/canvas/deps/insert.js +10 -4
  98. package/dist/canvas/deps/insert.js.map +1 -1
  99. package/dist/canvas/deps/pathEditCommits.js +189 -0
  100. package/dist/canvas/deps/pathEditCommits.js.map +1 -0
  101. package/dist/canvas/deps/snap.js +12 -9
  102. package/dist/canvas/deps/snap.js.map +1 -1
  103. package/dist/canvas/deps/transformFollowers.js +20 -0
  104. package/dist/canvas/deps/transformFollowers.js.map +1 -0
  105. package/dist/canvas/derivedPath.js +20 -1
  106. package/dist/canvas/derivedPath.js.map +1 -1
  107. package/dist/canvas/drawnBounds.js +38 -4
  108. package/dist/canvas/drawnBounds.js.map +1 -1
  109. package/dist/canvas/inheritedPaints.js +44 -0
  110. package/dist/canvas/inheritedPaints.js.map +1 -0
  111. package/dist/canvas/nodeShapes/derivedPainter.js +23 -16
  112. package/dist/canvas/nodeShapes/derivedPainter.js.map +1 -1
  113. package/dist/canvas/nodeShapes/nodePaint.js +13 -34
  114. package/dist/canvas/nodeShapes/nodePaint.js.map +1 -1
  115. package/dist/canvas/nodeShapes/pathPainter.js +12 -10
  116. package/dist/canvas/nodeShapes/pathPainter.js.map +1 -1
  117. package/dist/canvas/nodeShapes/rectFallbackPainter.js +4 -5
  118. package/dist/canvas/nodeShapes/rectFallbackPainter.js.map +1 -1
  119. package/dist/canvas/nodeShapes/shapePainter.js +12 -11
  120. package/dist/canvas/nodeShapes/shapePainter.js.map +1 -1
  121. package/dist/canvas/nodeShapes/textPainter.js +13 -12
  122. package/dist/canvas/nodeShapes/textPainter.js.map +1 -1
  123. package/dist/canvas/overlayRoleStrokes.js +12 -0
  124. package/dist/canvas/overlayRoleStrokes.js.map +1 -1
  125. package/dist/canvas/pathOverlay.js +27 -7
  126. package/dist/canvas/pathOverlay.js.map +1 -1
  127. package/dist/canvas/pickReach.js +3 -3
  128. package/dist/canvas/pickReach.js.map +1 -1
  129. package/dist/canvas/pickWalk.js +3 -1
  130. package/dist/canvas/pickWalk.js.map +1 -1
  131. package/dist/canvas/renderDebugSnapshot.js +1 -0
  132. package/dist/canvas/renderDebugSnapshot.js.map +1 -1
  133. package/dist/canvas/renderSceneToPixels.js +7 -6
  134. package/dist/canvas/renderSceneToPixels.js.map +1 -1
  135. package/dist/canvas/sceneAdapter.js.map +1 -1
  136. package/dist/canvas/sceneSlotWiring.js +2 -1
  137. package/dist/canvas/sceneSlotWiring.js.map +1 -1
  138. package/dist/canvas/sceneViewRender.js +2 -1
  139. package/dist/canvas/sceneViewRender.js.map +1 -1
  140. package/dist/canvas/surfaceContribution.js +12 -8
  141. package/dist/canvas/surfaceContribution.js.map +1 -1
  142. package/dist/canvas/useCanvasPaint.js +2 -1
  143. package/dist/canvas/useCanvasPaint.js.map +1 -1
  144. package/dist/canvas/useCanvasView.js +4 -2
  145. package/dist/canvas/useCanvasView.js.map +1 -1
  146. package/dist/canvas/useInFlightBounds.js +52 -0
  147. package/dist/canvas/useInFlightBounds.js.map +1 -0
  148. package/dist/canvas/useLayerStack.js +6 -2
  149. package/dist/canvas/useLayerStack.js.map +1 -1
  150. package/dist/canvas/useViewAim.js +121 -0
  151. package/dist/canvas/useViewAim.js.map +1 -0
  152. package/dist/canvas/useViewHelpers.js +7 -9
  153. package/dist/canvas/useViewHelpers.js.map +1 -1
  154. package/dist/canvas/useViewNesting.js +3 -2
  155. package/dist/canvas/useViewNesting.js.map +1 -1
  156. package/dist/canvas/useViewRegistrySurface.js +4 -2
  157. package/dist/canvas/useViewRegistrySurface.js.map +1 -1
  158. package/dist/canvas/viewMarkers.js +63 -0
  159. package/dist/canvas/viewMarkers.js.map +1 -0
  160. package/dist/canvas/viewRegistry.js +27 -1
  161. package/dist/canvas/viewRegistry.js.map +1 -1
  162. package/dist/clipboard.d.ts +3 -2
  163. package/dist/{clone-DZDrfIlU.d.ts → clone-C3e0OTuF.d.ts} +8 -21
  164. package/dist/clone.d.ts +4 -3
  165. package/dist/core/geometry/autoPoseDescriptor.js +1 -1
  166. package/dist/core/ops/setDependsOn.js +37 -0
  167. package/dist/core/ops/setDependsOn.js.map +1 -0
  168. package/dist/core/ops/writtenBy.js +53 -0
  169. package/dist/core/ops/writtenBy.js.map +1 -0
  170. package/dist/core/pages/fitViewToPage.js +12 -1
  171. package/dist/core/pages/fitViewToPage.js.map +1 -1
  172. package/dist/core/pages/pageEdits.js +163 -0
  173. package/dist/core/pages/pageEdits.js.map +1 -0
  174. package/dist/core/pages/pages.js +30 -1
  175. package/dist/core/pages/pages.js.map +1 -1
  176. package/dist/core/paint/meshKindLazy.js +59 -2
  177. package/dist/core/paint/meshKindLazy.js.map +1 -1
  178. package/dist/core/scene/NodeRouting.js +8 -3
  179. package/dist/core/scene/NodeRouting.js.map +1 -1
  180. package/dist/core/scene/arrivalWindow.js.map +1 -1
  181. package/dist/core/scene/carryDescendants.js +51 -0
  182. package/dist/core/scene/carryDescendants.js.map +1 -0
  183. package/dist/core/scene/clipNothing.js +13 -0
  184. package/dist/core/scene/clipNothing.js.map +1 -0
  185. package/dist/core/scene/depMemo.js +11 -3
  186. package/dist/core/scene/depMemo.js.map +1 -1
  187. package/dist/core/scene/dependents.js +7 -1
  188. package/dist/core/scene/dependents.js.map +1 -1
  189. package/dist/core/scene/derivedParts.js +10 -11
  190. package/dist/core/scene/derivedParts.js.map +1 -1
  191. package/dist/core/scene/docValues.js +57 -0
  192. package/dist/core/scene/docValues.js.map +1 -0
  193. package/dist/core/scene/editPass.js +111 -0
  194. package/dist/core/scene/editPass.js.map +1 -0
  195. package/dist/core/scene/effectivePose.js +13 -2
  196. package/dist/core/scene/effectivePose.js.map +1 -1
  197. package/dist/core/scene/fieldEdits.js +4 -1
  198. package/dist/core/scene/fieldEdits.js.map +1 -1
  199. package/dist/core/scene/fontReads.js +37 -0
  200. package/dist/core/scene/fontReads.js.map +1 -0
  201. package/dist/core/scene/historyFacade.js +1 -0
  202. package/dist/core/scene/historyFacade.js.map +1 -1
  203. package/dist/core/scene/inheritedPaint.js +75 -0
  204. package/dist/core/scene/inheritedPaint.js.map +1 -0
  205. package/dist/core/scene/kitRegistry.js +5 -0
  206. package/dist/core/scene/kitRegistry.js.map +1 -1
  207. package/dist/core/scene/layoutPass.js +28 -3
  208. package/dist/core/scene/layoutPass.js.map +1 -1
  209. package/dist/core/scene/nodeMemo.js +15 -7
  210. package/dist/core/scene/nodeMemo.js.map +1 -1
  211. package/dist/core/scene/pathEffects/blend.js.map +1 -1
  212. package/dist/core/scene/pathEffects/derive.js +7 -2
  213. package/dist/core/scene/pathEffects/derive.js.map +1 -1
  214. package/dist/core/scene/pathEffects/effects.js +3 -1
  215. package/dist/core/scene/pathEffects/effects.js.map +1 -1
  216. package/dist/core/scene/pathEffects/textAlong.js +95 -0
  217. package/dist/core/scene/pathEffects/textAlong.js.map +1 -0
  218. package/dist/core/scene/recorder.js +28 -19
  219. package/dist/core/scene/recorder.js.map +1 -1
  220. package/dist/core/scene/scene.js +15 -9
  221. package/dist/core/scene/scene.js.map +1 -1
  222. package/dist/core/scene/sceneChanges.js +13 -0
  223. package/dist/core/scene/sceneChanges.js.map +1 -0
  224. package/dist/core/scene/sceneEdits.js +8 -1
  225. package/dist/core/scene/sceneEdits.js.map +1 -1
  226. package/dist/core/scene/sceneMutators.js +1 -0
  227. package/dist/core/scene/sceneMutators.js.map +1 -1
  228. package/dist/core/scene/sceneRecording.js +20 -3
  229. package/dist/core/scene/sceneRecording.js.map +1 -1
  230. package/dist/core/scene/sceneSelection.js +4 -1
  231. package/dist/core/scene/sceneSelection.js.map +1 -1
  232. package/dist/core/scene/sceneState.js +11 -5
  233. package/dist/core/scene/sceneState.js.map +1 -1
  234. package/dist/core/scene/serialization.js +5 -3
  235. package/dist/core/scene/serialization.js.map +1 -1
  236. package/dist/core/scene/types.js.map +1 -1
  237. package/dist/core/scene/unitScopes.js +19 -1
  238. package/dist/core/scene/unitScopes.js.map +1 -1
  239. package/dist/core/selection/usePublishSceneSelection.js +6 -12
  240. package/dist/core/selection/usePublishSceneSelection.js.map +1 -1
  241. package/dist/core/shapeKinds.js +25 -11
  242. package/dist/core/shapeKinds.js.map +1 -1
  243. package/dist/{cornerHandles-Camw_yeu.d.ts → cornerHandles-p8fDIAKt.d.ts} +3 -2
  244. package/dist/debug/createDebugOverlayLayer.js +16 -111
  245. package/dist/debug/createDebugOverlayLayer.js.map +1 -1
  246. package/dist/debug/createDebugSink.js +2 -1
  247. package/dist/debug/createDebugSink.js.map +1 -1
  248. package/dist/debug/defaultTheme.js +4 -2
  249. package/dist/debug/defaultTheme.js.map +1 -1
  250. package/dist/debug/features.js +17 -0
  251. package/dist/debug/features.js.map +1 -0
  252. package/dist/debug/overlayPanels.js +117 -0
  253. package/dist/debug/overlayPanels.js.map +1 -0
  254. package/dist/debug/parseDebugFlags.js +4 -13
  255. package/dist/debug/parseDebugFlags.js.map +1 -1
  256. package/dist/{depSchema-Cgfu_G9s.d.ts → depSchema-mG19aEdD.d.ts} +174 -904
  257. package/dist/devtools/handlers.js +112 -0
  258. package/dist/devtools/handlers.js.map +1 -0
  259. package/dist/devtools/history.js +71 -0
  260. package/dist/devtools/history.js.map +1 -0
  261. package/dist/devtools/hook.js +74 -0
  262. package/dist/devtools/hook.js.map +1 -0
  263. package/dist/devtools/label.js +25 -0
  264. package/dist/devtools/label.js.map +1 -0
  265. package/dist/devtools/notices.js +58 -0
  266. package/dist/devtools/notices.js.map +1 -0
  267. package/dist/devtools/protocol.js +7 -0
  268. package/dist/devtools/protocol.js.map +1 -0
  269. package/dist/devtools/registry.js +90 -0
  270. package/dist/devtools/registry.js.map +1 -0
  271. package/dist/devtools/root.js +80 -0
  272. package/dist/devtools/root.js.map +1 -0
  273. package/dist/devtools/serialize.js +86 -0
  274. package/dist/devtools/serialize.js.map +1 -0
  275. package/dist/devtools/session.js +111 -0
  276. package/dist/devtools/session.js.map +1 -0
  277. package/dist/devtools/transport.js +67 -0
  278. package/dist/devtools/transport.js.map +1 -0
  279. package/dist/devtools/useDevtoolsRoot.js +81 -0
  280. package/dist/devtools/useDevtoolsRoot.js.map +1 -0
  281. package/dist/devtools-protocol.d.ts +435 -0
  282. package/dist/devtools-protocol.js +7 -0
  283. package/dist/devtools.d.ts +8 -0
  284. package/dist/devtools.js +12 -0
  285. package/dist/devtools.js.map +1 -0
  286. package/dist/features/chrome-caps/useHoverTracking.js +16 -10
  287. package/dist/features/chrome-caps/useHoverTracking.js.map +1 -1
  288. package/dist/features/ingestion/contentHandlers.js +25 -2
  289. package/dist/features/ingestion/contentHandlers.js.map +1 -1
  290. package/dist/features/measure/measureCommands.js +7 -5
  291. package/dist/features/measure/measureCommands.js.map +1 -1
  292. package/dist/features/measure/measureContribution.js +4 -2
  293. package/dist/features/measure/measureContribution.js.map +1 -1
  294. package/dist/features/modes/modeTriggers.js +7 -3
  295. package/dist/features/modes/modeTriggers.js.map +1 -1
  296. package/dist/features/pathEffects/effectSources.js +60 -0
  297. package/dist/features/pathEffects/effectSources.js.map +1 -0
  298. package/dist/features/pathEffects/readSource.js +17 -1
  299. package/dist/features/pathEffects/readSource.js.map +1 -1
  300. package/dist/features/pathEffects/textItems.js +53 -0
  301. package/dist/features/pathEffects/textItems.js.map +1 -0
  302. package/dist/features/pathEffects/useEffectSourcesLayer.js +57 -0
  303. package/dist/features/pathEffects/useEffectSourcesLayer.js.map +1 -0
  304. package/dist/features/paths/index.js +2 -2
  305. package/dist/features/paths/pathEditExtension.js.map +1 -1
  306. package/dist/features/paths/pathEditState.js +5 -2
  307. package/dist/features/paths/pathEditState.js.map +1 -1
  308. package/dist/features/paths/pathSnap/pathSnapSource.js +5 -5
  309. package/dist/features/paths/pathSnap/pathSnapSource.js.map +1 -1
  310. package/dist/features/paths/pathSnap/sceneIndex.js +10 -3
  311. package/dist/features/paths/pathSnap/sceneIndex.js.map +1 -1
  312. package/dist/features/selection/selectionPose.js +4 -1
  313. package/dist/features/selection/selectionPose.js.map +1 -1
  314. package/dist/features/snap/gather.js +9 -1
  315. package/dist/features/snap/gather.js.map +1 -1
  316. package/dist/features/snap/lazySession.js +17 -0
  317. package/dist/features/snap/lazySession.js.map +1 -0
  318. package/dist/features/snap/marks.js.map +1 -1
  319. package/dist/features/snap/probes2d.js +27 -19
  320. package/dist/features/snap/probes2d.js.map +1 -1
  321. package/dist/features/snap/readoutLayer.js.map +1 -1
  322. package/dist/features/snap/roles.js +2 -1
  323. package/dist/features/snap/roles.js.map +1 -1
  324. package/dist/features/snap/rotationSource.js +25 -8
  325. package/dist/features/snap/rotationSource.js.map +1 -1
  326. package/dist/features/snap/sceneSession2d.js +6 -4
  327. package/dist/features/snap/sceneSession2d.js.map +1 -1
  328. package/dist/features/snap/session2d.js +37 -23
  329. package/dist/features/snap/session2d.js.map +1 -1
  330. package/dist/features/snap/spanSnap.js +5 -2
  331. package/dist/features/snap/spanSnap.js.map +1 -1
  332. package/dist/features/text/sceneTextDrafts.js +65 -0
  333. package/dist/features/text/sceneTextDrafts.js.map +1 -0
  334. package/dist/features/text/textHitAt.js +31 -2
  335. package/dist/features/text/textHitAt.js.map +1 -1
  336. package/dist/features/text/useSceneTextEdit.js +22 -18
  337. package/dist/features/text/useSceneTextEdit.js.map +1 -1
  338. package/dist/features/viewports/aim.js +105 -0
  339. package/dist/features/viewports/aim.js.map +1 -0
  340. package/dist/features/viewports/viewMarker.js +82 -0
  341. package/dist/features/viewports/viewMarker.js.map +1 -0
  342. package/dist/features/viewports/viewMarkerDrag.js +55 -0
  343. package/dist/features/viewports/viewMarkerDrag.js.map +1 -0
  344. package/dist/icons.table.js +1 -1
  345. package/dist/icons.table.js.map +1 -1
  346. package/dist/icons.table.json +0 -10
  347. package/dist/index.d.ts +1198 -894
  348. package/dist/index.js +55 -38
  349. package/dist/interactions/actions/align/action.js +6 -4
  350. package/dist/interactions/actions/align/action.js.map +1 -1
  351. package/dist/interactions/actions/align/align.js.map +1 -1
  352. package/dist/interactions/actions/booleans/action.js +7 -1
  353. package/dist/interactions/actions/booleans/action.js.map +1 -1
  354. package/dist/interactions/actions/booleans/booleans.js +2 -1
  355. package/dist/interactions/actions/booleans/booleans.js.map +1 -1
  356. package/dist/interactions/actions/booleans/operands.js +6 -5
  357. package/dist/interactions/actions/booleans/operands.js.map +1 -1
  358. package/dist/interactions/actions/clipboard/action.js +27 -17
  359. package/dist/interactions/actions/clipboard/action.js.map +1 -1
  360. package/dist/interactions/actions/clone/action.js +1 -1
  361. package/dist/interactions/actions/clone/behaviors.js +4 -4
  362. package/dist/interactions/actions/clone/behaviors.js.map +1 -1
  363. package/dist/interactions/actions/defaults/anchorEditing.js +44 -23
  364. package/dist/interactions/actions/defaults/anchorEditing.js.map +1 -1
  365. package/dist/interactions/actions/defaults/anchorJoin.js +12 -6
  366. package/dist/interactions/actions/defaults/anchorJoin.js.map +1 -1
  367. package/dist/interactions/actions/defaults/bendSegment.js +8 -5
  368. package/dist/interactions/actions/defaults/bendSegment.js.map +1 -1
  369. package/dist/interactions/actions/defaults/cancelGesture.js +11 -8
  370. package/dist/interactions/actions/defaults/cancelGesture.js.map +1 -1
  371. package/dist/interactions/actions/defaults/contextMenu.js +17 -8
  372. package/dist/interactions/actions/defaults/contextMenu.js.map +1 -1
  373. package/dist/interactions/actions/defaults/createPaintAction.js +2 -2
  374. package/dist/interactions/actions/defaults/createPaintAction.js.map +1 -1
  375. package/dist/interactions/actions/defaults/delete.js +64 -41
  376. package/dist/interactions/actions/defaults/delete.js.map +1 -1
  377. package/dist/interactions/actions/defaults/duplicate.js +12 -9
  378. package/dist/interactions/actions/defaults/duplicate.js.map +1 -1
  379. package/dist/interactions/actions/defaults/enterPathEdit.js +19 -9
  380. package/dist/interactions/actions/defaults/enterPathEdit.js.map +1 -1
  381. package/dist/interactions/actions/defaults/escape.js +11 -8
  382. package/dist/interactions/actions/defaults/escape.js.map +1 -1
  383. package/dist/interactions/actions/defaults/exitPathEdit.js +7 -4
  384. package/dist/interactions/actions/defaults/exitPathEdit.js.map +1 -1
  385. package/dist/interactions/actions/defaults/group.js +21 -15
  386. package/dist/interactions/actions/defaults/group.js.map +1 -1
  387. package/dist/interactions/actions/defaults/ingest.js +17 -9
  388. package/dist/interactions/actions/defaults/ingest.js.map +1 -1
  389. package/dist/interactions/actions/defaults/insertPathAnchor.js +7 -4
  390. package/dist/interactions/actions/defaults/insertPathAnchor.js.map +1 -1
  391. package/dist/interactions/actions/defaults/nudge.js +21 -40
  392. package/dist/interactions/actions/defaults/nudge.js.map +1 -1
  393. package/dist/interactions/actions/defaults/pathEditTools.js +11 -8
  394. package/dist/interactions/actions/defaults/pathEditTools.js.map +1 -1
  395. package/dist/interactions/actions/defaults/pinchZoom.js +7 -4
  396. package/dist/interactions/actions/defaults/pinchZoom.js.map +1 -1
  397. package/dist/interactions/actions/defaults/reorder.js +24 -6
  398. package/dist/interactions/actions/defaults/reorder.js.map +1 -1
  399. package/dist/interactions/actions/defaults/selectAll.js +8 -5
  400. package/dist/interactions/actions/defaults/selectAll.js.map +1 -1
  401. package/dist/interactions/actions/defaults/setFill.js +7 -3
  402. package/dist/interactions/actions/defaults/setFill.js.map +1 -1
  403. package/dist/interactions/actions/defaults/setFillOpacity.js +1 -1
  404. package/dist/interactions/actions/defaults/setStroke.js +12 -11
  405. package/dist/interactions/actions/defaults/setStroke.js.map +1 -1
  406. package/dist/interactions/actions/defaults/setStrokeOpacity.js +1 -1
  407. package/dist/interactions/actions/defaults/toolActivate.js +7 -1
  408. package/dist/interactions/actions/defaults/toolActivate.js.map +1 -1
  409. package/dist/interactions/actions/defaults/toolResetToDefault.js +7 -4
  410. package/dist/interactions/actions/defaults/toolResetToDefault.js.map +1 -1
  411. package/dist/interactions/actions/defaults/undoRedo.js +19 -13
  412. package/dist/interactions/actions/defaults/undoRedo.js.map +1 -1
  413. package/dist/interactions/actions/defaults/viewportWheelPan.js +16 -7
  414. package/dist/interactions/actions/defaults/viewportWheelPan.js.map +1 -1
  415. package/dist/interactions/actions/defaults/viewportZoom.js +24 -6
  416. package/dist/interactions/actions/defaults/viewportZoom.js.map +1 -1
  417. package/dist/interactions/actions/distribute/action.js +6 -4
  418. package/dist/interactions/actions/distribute/action.js.map +1 -1
  419. package/dist/interactions/actions/drawnBoxes.js +2 -1
  420. package/dist/interactions/actions/drawnBoxes.js.map +1 -1
  421. package/dist/interactions/actions/edit-anchors/action.js +10 -10
  422. package/dist/interactions/actions/edit-anchors/action.js.map +1 -1
  423. package/dist/interactions/actions/edit-anchors/preview.js +41 -8
  424. package/dist/interactions/actions/edit-anchors/preview.js.map +1 -1
  425. package/dist/interactions/actions/flip/action.js +14 -6
  426. package/dist/interactions/actions/flip/action.js.map +1 -1
  427. package/dist/interactions/actions/gestureLifecycle.js +5 -2
  428. package/dist/interactions/actions/gestureLifecycle.js.map +1 -1
  429. package/dist/interactions/actions/insert/action.js +1 -2
  430. package/dist/interactions/actions/insert/action.js.map +1 -1
  431. package/dist/interactions/actions/insert/commit.js +1 -1
  432. package/dist/interactions/actions/insert/parent.js +11 -0
  433. package/dist/interactions/actions/insert/parent.js.map +1 -0
  434. package/dist/interactions/actions/insert/placeAction.js +7 -2
  435. package/dist/interactions/actions/insert/placeAction.js.map +1 -1
  436. package/dist/interactions/actions/insert/repositionAction.js +2 -1
  437. package/dist/interactions/actions/insert/repositionAction.js.map +1 -1
  438. package/dist/interactions/actions/insert/session.js +5 -1
  439. package/dist/interactions/actions/insert/session.js.map +1 -1
  440. package/dist/interactions/actions/move/action.js +15 -8
  441. package/dist/interactions/actions/move/action.js.map +1 -1
  442. package/dist/interactions/actions/move/behaviors/layoutDrop.js +0 -1
  443. package/dist/interactions/actions/move/behaviors/layoutDrop.js.map +1 -1
  444. package/dist/interactions/actions/move/behaviors/snapToContainer.js +1 -1
  445. package/dist/interactions/actions/move/capture.js +1 -1
  446. package/dist/interactions/actions/move/commit/index.js +0 -2
  447. package/dist/interactions/actions/move/commit/index.js.map +1 -1
  448. package/dist/interactions/actions/move/commit/layoutDrop.js +2 -2
  449. package/dist/interactions/actions/move/commit/layoutRelease.js +2 -2
  450. package/dist/interactions/actions/move/commit/reparent.js +11 -5
  451. package/dist/interactions/actions/move/commit/reparent.js.map +1 -1
  452. package/dist/interactions/actions/move/frame.js +4 -10
  453. package/dist/interactions/actions/move/frame.js.map +1 -1
  454. package/dist/interactions/actions/move/landedDescendants.js +20 -17
  455. package/dist/interactions/actions/move/landedDescendants.js.map +1 -1
  456. package/dist/interactions/actions/move/layout/container.js +2 -1
  457. package/dist/interactions/actions/move/layout/container.js.map +1 -1
  458. package/dist/interactions/actions/move/layout/dragged.js +1 -1
  459. package/dist/interactions/actions/move/layout/dropPass.js +18 -1
  460. package/dist/interactions/actions/move/layout/dropPass.js.map +1 -1
  461. package/dist/interactions/actions/move/layout/exits.js +5 -5
  462. package/dist/interactions/actions/move/layout/exits.js.map +1 -1
  463. package/dist/interactions/actions/move/session.js +14 -3
  464. package/dist/interactions/actions/move/session.js.map +1 -1
  465. package/dist/interactions/actions/move/translate.js +8 -37
  466. package/dist/interactions/actions/move/translate.js.map +1 -1
  467. package/dist/interactions/actions/moveNodes.js +87 -0
  468. package/dist/interactions/actions/moveNodes.js.map +1 -0
  469. package/dist/interactions/actions/outlines/createOutlinesAction.js +8 -5
  470. package/dist/interactions/actions/outlines/createOutlinesAction.js.map +1 -1
  471. package/dist/interactions/actions/outlines/outlineStroke.js +5 -3
  472. package/dist/interactions/actions/outlines/outlineStroke.js.map +1 -1
  473. package/dist/interactions/actions/pathCommands/cutJoin.js +8 -5
  474. package/dist/interactions/actions/pathCommands/cutJoin.js.map +1 -1
  475. package/dist/interactions/actions/planeInput.js.map +1 -1
  476. package/dist/interactions/actions/resize/action.js +83 -72
  477. package/dist/interactions/actions/resize/action.js.map +1 -1
  478. package/dist/interactions/actions/resize/commit.js +2 -1
  479. package/dist/interactions/actions/resize/commit.js.map +1 -1
  480. package/dist/interactions/actions/resize/cornerHandles.js +2 -1
  481. package/dist/interactions/actions/resize/cornerHandles.js.map +1 -1
  482. package/dist/interactions/actions/resize/session.js +2 -0
  483. package/dist/interactions/actions/resize/session.js.map +1 -1
  484. package/dist/interactions/actions/resolvePreviews.js +3 -3
  485. package/dist/interactions/actions/resolvePreviews.js.map +1 -1
  486. package/dist/interactions/actions/rotate/action.js +7 -4
  487. package/dist/interactions/actions/rotate/action.js.map +1 -1
  488. package/dist/interactions/actions/rotate/commit.js +2 -1
  489. package/dist/interactions/actions/rotate/commit.js.map +1 -1
  490. package/dist/interactions/actions/rotate/session.js +2 -0
  491. package/dist/interactions/actions/rotate/session.js.map +1 -1
  492. package/dist/interactions/actions/selectionSubtree.js +25 -9
  493. package/dist/interactions/actions/selectionSubtree.js.map +1 -1
  494. package/dist/interactions/actions/testUtils.js.map +1 -1
  495. package/dist/interactions/actions/transform-again/action.js +13 -11
  496. package/dist/interactions/actions/transform-again/action.js.map +1 -1
  497. package/dist/interactions/actions/transformFinish.js +106 -0
  498. package/dist/interactions/actions/transformFinish.js.map +1 -0
  499. package/dist/json.d.ts +4 -0
  500. package/dist/json.js +3 -0
  501. package/dist/kitSettingsSchema.js +8 -5
  502. package/dist/kitSettingsSchema.js.map +1 -1
  503. package/dist/{math-CrJULaZI.d.ts → math-B56zxVs5.d.ts} +10 -1
  504. package/dist/math.d.ts +1 -1
  505. package/dist/math.js +2 -1
  506. package/dist/move.d.ts +5 -4
  507. package/dist/{options-p9GZMXbY.d.ts → options-DBxEryYq.d.ts} +1 -1
  508. package/dist/resize.d.ts +4 -3
  509. package/dist/routing.d.ts +1 -1
  510. package/dist/routing.js +2 -2
  511. package/dist/test-hook/createTestHook.js +1 -1
  512. package/dist/test-hook/createTestHook.js.map +1 -1
  513. package/dist/test-hook/useTestHook.js +2 -1
  514. package/dist/test-hook/useTestHook.js.map +1 -1
  515. package/dist/test-seams.d.ts +9 -5
  516. package/dist/tools/builtin/ellipse/useEllipseTool.js +1 -0
  517. package/dist/tools/builtin/ellipse/useEllipseTool.js.map +1 -1
  518. package/dist/tools/builtin/eyedropper/useEyedropperTool.js +2 -1
  519. package/dist/tools/builtin/eyedropper/useEyedropperTool.js.map +1 -1
  520. package/dist/tools/builtin/hand/dragPanContribution.js +4 -1
  521. package/dist/tools/builtin/hand/dragPanContribution.js.map +1 -1
  522. package/dist/tools/builtin/hand/useHandTool.js +7 -4
  523. package/dist/tools/builtin/hand/useHandTool.js.map +1 -1
  524. package/dist/tools/builtin/image/useImageTool.js +1 -0
  525. package/dist/tools/builtin/image/useImageTool.js.map +1 -1
  526. package/dist/tools/builtin/lasso/useLassoTool.js +1 -0
  527. package/dist/tools/builtin/lasso/useLassoTool.js.map +1 -1
  528. package/dist/tools/builtin/line/useLineTool.js +1 -0
  529. package/dist/tools/builtin/line/useLineTool.js.map +1 -1
  530. package/dist/tools/builtin/measure/useMeasureTool.js +12 -5
  531. package/dist/tools/builtin/measure/useMeasureTool.js.map +1 -1
  532. package/dist/tools/builtin/pen/penHandle.js +3 -5
  533. package/dist/tools/builtin/pen/penHandle.js.map +1 -1
  534. package/dist/tools/builtin/pen/usePenTool.js +14 -6
  535. package/dist/tools/builtin/pen/usePenTool.js.map +1 -1
  536. package/dist/tools/builtin/pencil/usePencilTool.js +1 -0
  537. package/dist/tools/builtin/pencil/usePencilTool.js.map +1 -1
  538. package/dist/tools/builtin/polygon/usePolygonTool.js +13 -4
  539. package/dist/tools/builtin/polygon/usePolygonTool.js.map +1 -1
  540. package/dist/tools/builtin/rect/useRectTool.js +1 -0
  541. package/dist/tools/builtin/rect/useRectTool.js.map +1 -1
  542. package/dist/tools/builtin/select/adapterPointQuery.js +3 -2
  543. package/dist/tools/builtin/select/adapterPointQuery.js.map +1 -1
  544. package/dist/tools/builtin/select/pressDecision.js +32 -0
  545. package/dist/tools/builtin/select/pressDecision.js.map +1 -0
  546. package/dist/tools/builtin/select/selectionContributions.js +22 -13
  547. package/dist/tools/builtin/select/selectionContributions.js.map +1 -1
  548. package/dist/tools/builtin/select/useSelectTool.js +13 -10
  549. package/dist/tools/builtin/select/useSelectTool.js.map +1 -1
  550. package/dist/tools/builtin/slice/useSliceTool.js +22 -8
  551. package/dist/tools/builtin/slice/useSliceTool.js.map +1 -1
  552. package/dist/tools/builtin/star/useStarTool.js +13 -4
  553. package/dist/tools/builtin/star/useStarTool.js.map +1 -1
  554. package/dist/tools/builtin/sticky/stickyNode.js +4 -1
  555. package/dist/tools/builtin/sticky/stickyNode.js.map +1 -1
  556. package/dist/tools/builtin/sticky/useStickyTool.js +10 -5
  557. package/dist/tools/builtin/sticky/useStickyTool.js.map +1 -1
  558. package/dist/tools/builtin/text/useTextTool.js +3 -1
  559. package/dist/tools/builtin/text/useTextTool.js.map +1 -1
  560. package/dist/tools/index.js +26 -0
  561. package/dist/{types-CHVXGfYm.d.ts → types-7puAuVD2.d.ts} +3 -262
  562. package/dist/types-BN9hbdMI.d.ts +184 -0
  563. package/dist/types-CniVctmk.d.ts +949 -0
  564. package/dist/types-oFeQ5VjV.d.ts +264 -0
  565. package/dist/util/paint.js +1 -3
  566. package/dist/util/paint.js.map +1 -1
  567. package/dist/version.js +1 -1
  568. package/package.json +39 -25
  569. package/dist/canvas/SceneCanvas/useBuiltinRigTools.js +0 -65
  570. package/dist/canvas/SceneCanvas/useBuiltinRigTools.js.map +0 -1
  571. package/dist/tools/builtin/bone/boneActions.js +0 -156
  572. package/dist/tools/builtin/bone/boneActions.js.map +0 -1
  573. package/dist/tools/builtin/bone/boneOverlay.js +0 -71
  574. package/dist/tools/builtin/bone/boneOverlay.js.map +0 -1
  575. package/dist/tools/builtin/bone/placedRig.js +0 -28
  576. package/dist/tools/builtin/bone/placedRig.js.map +0 -1
  577. package/dist/tools/builtin/bone/rigEditState.js +0 -30
  578. package/dist/tools/builtin/bone/rigEditState.js.map +0 -1
  579. package/dist/tools/builtin/bone/useBoneTool.js +0 -125
  580. package/dist/tools/builtin/bone/useBoneTool.js.map +0 -1
  581. package/dist/tools/builtin/weight/useWeightTool.js +0 -101
  582. package/dist/tools/builtin/weight/useWeightTool.js.map +0 -1
  583. package/dist/tools/builtin/weight/weightActions.js +0 -140
  584. package/dist/tools/builtin/weight/weightActions.js.map +0 -1
  585. package/dist/tools/builtin/weight/weightOverlay.js +0 -78
  586. package/dist/tools/builtin/weight/weightOverlay.js.map +0 -1
@@ -17,7 +17,12 @@ import { useMemo } from "react";
17
17
  * caller's own api is not wrapped and still writes.
18
18
  */
19
19
  function useCanvasSelection(args) {
20
- const { scene, supplied, options, selectable, describeKind } = args;
20
+ const { scene, selectable, kindOf } = args;
21
+ const { selection: supplied, selectionOptions: options, describeKind } = args.props;
22
+ const describe = useMemo(() => describeKind ?? (kindOf && ((node) => {
23
+ const kind = kindOf(node);
24
+ return kind === "unknown" ? void 0 : kind;
25
+ })), [describeKind, kindOf]);
21
26
  const derivedOptions = useMemo(() => ({
22
27
  scene,
23
28
  ...options ?? {}
@@ -25,7 +30,7 @@ function useCanvasSelection(args) {
25
30
  const internal = useSelection(derivedOptions);
26
31
  const base = supplied ?? internal;
27
32
  const selection = selectable ? base : readOnlySelection(base);
28
- usePublishSceneSelection(scene, selection.current, describeKind);
33
+ usePublishSceneSelection(scene, selection.current, describe);
29
34
  return selection;
30
35
  }
31
36
 
@@ -1 +1 @@
1
- {"version":3,"file":"useCanvasSelection.js","names":[],"sources":["../../../src/canvas/SceneCanvas/useCanvasSelection.ts"],"sourcesContent":["import { useMemo } from 'react';\nimport type { Node, NodeId, Scene } from 'core/scene/types';\nimport { readOnlySelection } from 'core/selection/readOnlySelection';\nimport { usePublishSceneSelection } from 'core/selection/usePublishSceneSelection';\nimport { useSelection, type SelectionApi, type UseSelectionOptions } from 'core/selection/useSelection';\n\n/**\n * The canvas's selection, published to any surrounding selection context.\n *\n * A caller-supplied api wins, and the one built here is then unused. The\n * built one is bound to the scene, so the selection an edit was made under\n * rides on the scene's history entries and undo can put it back.\n *\n * Everything the kit writes selection through (the `selection` dep, the\n * adapter's `setSelection`, ops committed through either) reads the returned\n * api, so on an unselectable canvas every write path here is closed. The\n * caller's own api is not wrapped and still writes.\n */\nexport function useCanvasSelection<TData, TLayer extends string, TPose>(args: {\n scene: Scene<TData, TLayer, TPose>;\n /** `<SceneCanvas selection>`. */\n supplied: SelectionApi | undefined;\n options: UseSelectionOptions | undefined;\n selectable: boolean;\n describeKind: ((node: Node<TData, TLayer, TPose>) => string | undefined) | undefined;\n}): SelectionApi {\n const { scene, supplied, options, selectable, describeKind } = args;\n const derivedOptions = useMemo<UseSelectionOptions>(\n () => ({ scene, ...(options ?? {}) }),\n [scene, options],\n );\n const internal = useSelection(derivedOptions);\n const base = supplied ?? internal;\n const selection = selectable ? base : readOnlySelection(base);\n usePublishSceneSelection(scene, selection.current as readonly NodeId[], describeKind);\n return selection;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAkBA,SAAgB,mBAAwD,MAOvD;CACf,MAAM,EAAE,OAAO,UAAU,SAAS,YAAY,iBAAiB;CAC/D,MAAM,iBAAiB,eACd;EAAE;EAAO,GAAI,WAAW,CAAC;CAAG,IACnC,CAAC,OAAO,OAAO,CACjB;CACA,MAAM,WAAW,aAAa,cAAc;CAC5C,MAAM,OAAO,YAAY;CACzB,MAAM,YAAY,aAAa,OAAO,kBAAkB,IAAI;CAC5D,yBAAyB,OAAO,UAAU,SAA8B,YAAY;CACpF,OAAO;AACT"}
1
+ {"version":3,"file":"useCanvasSelection.js","names":[],"sources":["../../../src/canvas/SceneCanvas/useCanvasSelection.ts"],"sourcesContent":["import { useMemo } from 'react';\nimport type { Node, NodeId, Scene } from 'core/scene/types';\nimport { readOnlySelection } from 'core/selection/readOnlySelection';\nimport { usePublishSceneSelection } from 'core/selection/usePublishSceneSelection';\nimport { useSelection, type SelectionApi, type UseSelectionOptions } from 'core/selection/useSelection';\nimport type { SceneCanvasProps } from './props';\n\n/**\n * The canvas's selection, published to any surrounding selection context.\n *\n * A caller-supplied api wins, and the one built here is then unused. The\n * built one is bound to the scene, so the selection an edit was made under\n * rides on the scene's history entries and undo can put it back.\n *\n * Everything the kit writes selection through (the `selection` dep, the\n * adapter's `setSelection`, ops committed through either) reads the returned\n * api, so on an unselectable canvas every write path here is closed. The\n * caller's own api is not wrapped and still writes.\n */\nexport function useCanvasSelection<TData, TLayer extends string, TPose>(args: {\n scene: Scene<TData, TLayer, TPose>;\n props: Pick<SceneCanvasProps<TData, TLayer, TPose>, 'selection' | 'selectionOptions' | 'describeKind'>;\n selectable: boolean;\n /** The canvas's routing kind, published for each node unless `describeKind` is given. */\n kindOf: ((node: { kind: string; data: TData }) => string) | undefined;\n}): SelectionApi {\n const { scene, selectable, kindOf } = args;\n const { selection: supplied, selectionOptions: options, describeKind } = args.props;\n const describe = useMemo(() => describeKind ?? (kindOf && ((node: Node<TData, TLayer, TPose>) => {\n const kind = kindOf(node);\n return kind === 'unknown' ? undefined : kind;\n })), [describeKind, kindOf]);\n const derivedOptions = useMemo<UseSelectionOptions>(\n () => ({ scene, ...(options ?? {}) }),\n [scene, options],\n );\n const internal = useSelection(derivedOptions);\n const base = supplied ?? internal;\n const selection = selectable ? base : readOnlySelection(base);\n usePublishSceneSelection(scene, selection.current as readonly NodeId[], describe);\n return selection;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAmBA,SAAgB,mBAAwD,MAMvD;CACf,MAAM,EAAE,OAAO,YAAY,WAAW;CACtC,MAAM,EAAE,WAAW,UAAU,kBAAkB,SAAS,iBAAiB,KAAK;CAC9E,MAAM,WAAW,cAAc,iBAAiB,YAAY,SAAqC;EAC/F,MAAM,OAAO,OAAO,IAAI;EACxB,OAAO,SAAS,YAAY,SAAY;CAC1C,KAAK,CAAC,cAAc,MAAM,CAAC;CAC3B,MAAM,iBAAiB,eACd;EAAE;EAAO,GAAI,WAAW,CAAC;CAAG,IACnC,CAAC,OAAO,OAAO,CACjB;CACA,MAAM,WAAW,aAAa,cAAc;CAC5C,MAAM,OAAO,YAAY;CACzB,MAAM,YAAY,aAAa,OAAO,kBAAkB,IAAI;CAC5D,yBAAyB,OAAO,UAAU,SAA8B,QAAQ;CAChF,OAAO;AACT"}
@@ -1,8 +1,9 @@
1
+ import { createViewMarkerContribution } from "../../features/viewports/viewMarkerDrag.js";
1
2
  import { createLongPressFeedbackContribution } from "../../features/longPress/longPressFeedback.js";
2
3
  import { useTools } from "../../tools/overlayBinding.js";
3
4
  import { presetActions, presetAmbient, presetContributions, resolveFeatures } from "./features.js";
4
5
  import { useBuiltinTools } from "./useBuiltinTools.js";
5
- import { useCallback, useEffect, useMemo } from "react";
6
+ import { useEffect, useMemo } from "react";
6
7
  import { useLatest } from "@weasel-js/react";
7
8
 
8
9
  //#region src/canvas/SceneCanvas/useCanvasTools.ts
@@ -21,12 +22,16 @@ var entryKey = (e) => {
21
22
  };
22
23
  /** The presets a canvas runs with. Keyed on the entries, not the array, so
23
24
  * an inline `features={['draw', pathTools]}` does not re-derive every render. */
24
- function useEnabledFeatures(features, named, hasViewport) {
25
+ function useEnabledFeatures(features, named, hasViewport, selectRotates) {
25
26
  const featuresKey = (features ?? []).map(entryKey).join("|");
26
- return useMemo(() => resolveFeatures(features, named, { viewport: hasViewport }), [
27
+ return useMemo(() => resolveFeatures(features, named, {
28
+ viewport: hasViewport,
29
+ selectRotates
30
+ }), [
27
31
  featuresKey,
28
32
  named,
29
- hasViewport
33
+ hasViewport,
34
+ selectRotates
30
35
  ]);
31
36
  }
32
37
  /**
@@ -37,12 +42,8 @@ function useEnabledFeatures(features, named, hasViewport) {
37
42
  function useCanvasTools(args) {
38
43
  const { select, enabled, tools: toolsProp, defaultTools, toolOptions, inertia, ambient, initialActiveTool, modes, onToolsCreated } = args;
39
44
  const takeover = toolsProp && isToolsApi(toolsProp) ? toolsProp : null;
40
- const selectionRef = useLatest(args.selection);
41
- const selected = useCallback(() => selectionRef.current.get(), [selectionRef]);
42
45
  const registry = useBuiltinTools({
43
46
  select,
44
- scene: args.scene,
45
- selection: selected,
46
47
  enabled,
47
48
  defaultTools,
48
49
  patch: toolsProp && !isToolsApi(toolsProp) ? toolsProp : null,
@@ -52,14 +53,18 @@ function useCanvasTools(args) {
52
53
  const defaultPressFeedback = useMemo(() => createLongPressFeedbackContribution(), []);
53
54
  const feedbackOpt = args.pressFeedback ?? true;
54
55
  const pressFeedback = feedbackOpt === true ? defaultPressFeedback : feedbackOpt || null;
56
+ const defaultMarkerDrag = useMemo(() => createViewMarkerContribution(), []);
57
+ const markerDrag = args.actions === null ? null : defaultMarkerDrag;
55
58
  const mergedAmbient = useMemo(() => [
56
59
  ...presetContributions(enabled),
57
60
  ...ambient ?? [],
58
- ...pressFeedback ? [pressFeedback] : []
61
+ ...pressFeedback ? [pressFeedback] : [],
62
+ ...markerDrag ? [markerDrag] : []
59
63
  ], [
60
64
  enabled,
61
65
  ambient,
62
- pressFeedback
66
+ pressFeedback,
67
+ markerDrag
63
68
  ]);
64
69
  const internal = useTools({
65
70
  active: initialActiveTool ?? ("select" in registry ? "select" : null),
@@ -1 +1 @@
1
- {"version":3,"file":"useCanvasTools.js","names":[],"sources":["../../../src/canvas/SceneCanvas/useCanvasTools.ts"],"sourcesContent":["import { useCallback, useEffect, useMemo } from 'react';\nimport { useLatest } from '@weasel-js/react';\nimport type { Action, SelectionApi } from '@weasel-js/routing';\nimport type { Scene } from 'core/scene/types';\nimport { createLongPressFeedbackContribution } from '../../features/longPress/longPressFeedback';\nimport { useTools, type Contribution, type Tool, type ToolsApi } from '../../tools/overlayBinding';\nimport {\n presetActions,\n presetAmbient,\n presetContributions,\n resolveFeatures,\n type EnabledPresets,\n type FeatureBindingOptions,\n type FeatureEntry,\n type NamedPresets,\n} from './features';\nimport type { SceneCanvasProps } from './props';\nimport type { ToolsPatch } from './toolRegistry';\nimport { useBuiltinTools } from './useBuiltinTools';\n\ntype Props = SceneCanvasProps<unknown, string, unknown>;\n\n/** Discriminate the polymorphic `tools` prop: `ToolsApi` has `setActive`\n * / `active` / `registry`; the patch record shape has none of those. */\nfunction isToolsApi(tools: ToolsApi | ToolsPatch): tools is ToolsApi {\n return typeof (tools as ToolsApi).setActive === 'function';\n}\n\nconst presetSerials = new WeakMap<object, number>();\nlet nextSerial = 0;\nconst entryKey = (e: FeatureEntry): string => {\n if (typeof e === 'string') return e;\n let n = presetSerials.get(e);\n if (n === undefined) presetSerials.set(e, (n = nextSerial++));\n return `#${n}`;\n};\n\n/** The presets a canvas runs with. Keyed on the entries, not the array, so\n * an inline `features={['draw', pathTools]}` does not re-derive every render. */\nexport function useEnabledFeatures(\n features: readonly FeatureEntry[] | undefined,\n named: NamedPresets | null,\n hasViewport: boolean,\n): EnabledPresets {\n const featuresKey = (features ?? []).map(entryKey).join('|');\n return useMemo(\n () => resolveFeatures(features, named, { viewport: hasViewport }),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [featuresKey, named, hasViewport],\n );\n}\n\n/**\n * The canvas's tools: a caller's own `ToolsApi` when the `tools` prop is one\n * (the takeover form), and otherwise the built-ins the presets and\n * `defaultTools` name, patched by a `tools` record.\n */\nexport function useCanvasTools(args: {\n /** The canvas's select tool, which is built from its scene and pickers. */\n select: Tool;\n /** The canvas's scene and selection, which the rig tools edit and read. */\n scene: Scene<unknown, string, unknown>;\n selection: SelectionApi;\n enabled: EnabledPresets;\n tools: Props['tools'];\n defaultTools: Props['defaultTools'];\n toolOptions: Props['toolOptions'];\n /** `viewport.inertia`, which is the hand tool's. */\n inertia: NonNullable<Props['viewport']>['inertia'];\n ambient: Props['ambient'];\n /** `longPress.feedback`. Default true, which installs the kit's own. */\n pressFeedback: NonNullable<Props['longPress']>['feedback'];\n initialActiveTool: Props['initialActiveTool'];\n modes: Props['modes'];\n onToolsCreated: Props['onToolsCreated'];\n}): {\n /** What the canvas routes input through: the takeover, or `internal`. */\n tools: ToolsApi;\n /** The canvas's own api, built whether or not a takeover replaces it. */\n internal: ToolsApi;\n takeover: ToolsApi | null;\n} {\n const { select, enabled, tools: toolsProp, defaultTools, toolOptions, inertia, ambient, initialActiveTool, modes, onToolsCreated } = args;\n\n const takeover = toolsProp && isToolsApi(toolsProp) ? toolsProp : null;\n const selectionRef = useLatest(args.selection);\n const selected = useCallback(() => selectionRef.current.get(), [selectionRef]);\n const registry = useBuiltinTools({\n select,\n scene: args.scene,\n selection: selected,\n enabled,\n defaultTools,\n patch: toolsProp && !isToolsApi(toolsProp) ? toolsProp : null,\n toolOptions,\n inertia,\n });\n\n const defaultPressFeedback = useMemo(() => createLongPressFeedbackContribution(), []);\n const feedbackOpt = args.pressFeedback ?? true;\n const pressFeedback = feedbackOpt === true ? defaultPressFeedback : feedbackOpt || null;\n const mergedAmbient = useMemo(\n () => [...presetContributions(enabled), ...(ambient ?? []), ...(pressFeedback ? [pressFeedback] : [])],\n [enabled, ambient, pressFeedback],\n );\n\n const internal = useTools({\n active: initialActiveTool ?? ('select' in registry ? 'select' : null),\n registry,\n ...(mergedAmbient.length ? { ambient: mergedAmbient } : {}),\n ...(modes ? { modes } : {}),\n });\n const tools = takeover ?? internal;\n\n const onToolsCreatedRef = useLatest(onToolsCreated);\n useEffect(() => { onToolsCreatedRef.current?.(tools); }, [tools, onToolsCreatedRef]);\n\n return { tools, internal, takeover };\n}\n\n/**\n * The presets' ambient bindings, and the standard actions the canvas\n * registers. The bindings are not tools and sit outside `tools`, so they apply\n * under a takeover too. An action is registered when an enabled preset brings\n * it, or when it is in `pool` and a tool or contribution on this canvas binds\n * it: a tool brings the actions it routes to, so `defaultTools={['rect']}`\n * works under any preset.\n */\nexport function useFeatureBindings(args: {\n enabled: EnabledPresets;\n /** Actions registered only when something binds them. */\n pool: readonly Action[];\n tools: Pick<ToolsApi, 'registry' | 'ambient'>;\n move: FeatureBindingOptions['move'];\n rotate: FeatureBindingOptions['rotate'];\n}): { contributions: Contribution[]; standardActions: Action[] } {\n const { enabled, pool, tools, move, rotate } = args;\n const contributions = useMemo<Contribution[]>(\n () => presetAmbient(enabled, { move, rotate }),\n [enabled, move, rotate],\n );\n const standardActions = useMemo(() => {\n const out = presetActions(enabled);\n const have = new Set(out.map((a) => a.id));\n const bound = new Set<string>();\n for (const entry of [...Object.values(tools.registry), ...tools.ambient, ...contributions]) {\n for (const b of entry.bindings ?? []) bound.add(b.actionId);\n }\n for (const a of pool) {\n if (bound.has(a.id) && !have.has(a.id)) {\n have.add(a.id);\n out.push(a);\n }\n }\n return out;\n }, [enabled, pool, tools, contributions]);\n return { contributions, standardActions };\n}\n\n"],"mappings":"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"}
1
+ {"version":3,"file":"useCanvasTools.js","names":[],"sources":["../../../src/canvas/SceneCanvas/useCanvasTools.ts"],"sourcesContent":["import { useEffect, useMemo } from 'react';\nimport { useLatest } from '@weasel-js/react';\nimport type { Action } from '@weasel-js/routing';\nimport { createLongPressFeedbackContribution } from '../../features/longPress/longPressFeedback';\nimport { createViewMarkerContribution } from '../../features/viewports/viewMarkerDrag';\nimport { useTools, type Contribution, type Tool, type ToolsApi } from '../../tools/overlayBinding';\nimport {\n presetActions,\n presetAmbient,\n presetContributions,\n resolveFeatures,\n type EnabledPresets,\n type FeatureBindingOptions,\n type FeatureEntry,\n type NamedPresets,\n} from './features';\nimport type { SceneCanvasProps } from './props';\nimport type { ToolsPatch } from './toolRegistry';\nimport { useBuiltinTools } from './useBuiltinTools';\n\ntype Props = SceneCanvasProps<unknown, string, unknown>;\n\n/** Discriminate the polymorphic `tools` prop: `ToolsApi` has `setActive`\n * / `active` / `registry`; the patch record shape has none of those. */\nfunction isToolsApi(tools: ToolsApi | ToolsPatch): tools is ToolsApi {\n return typeof (tools as ToolsApi).setActive === 'function';\n}\n\nconst presetSerials = new WeakMap<object, number>();\nlet nextSerial = 0;\nconst entryKey = (e: FeatureEntry): string => {\n if (typeof e === 'string') return e;\n let n = presetSerials.get(e);\n if (n === undefined) presetSerials.set(e, (n = nextSerial++));\n return `#${n}`;\n};\n\n/** The presets a canvas runs with. Keyed on the entries, not the array, so\n * an inline `features={['draw', pathTools]}` does not re-derive every render. */\nexport function useEnabledFeatures(\n features: readonly FeatureEntry[] | undefined,\n named: NamedPresets | null,\n hasViewport: boolean,\n selectRotates: boolean,\n): EnabledPresets {\n const featuresKey = (features ?? []).map(entryKey).join('|');\n return useMemo(\n () => resolveFeatures(features, named, { viewport: hasViewport, selectRotates }),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [featuresKey, named, hasViewport, selectRotates],\n );\n}\n\n/**\n * The canvas's tools: a caller's own `ToolsApi` when the `tools` prop is one\n * (the takeover form), and otherwise the built-ins the presets and\n * `defaultTools` name, patched by a `tools` record.\n */\nexport function useCanvasTools(args: {\n /** The canvas's select tool, which is built from its scene and pickers. */\n select: Tool;\n enabled: EnabledPresets;\n tools: Props['tools'];\n defaultTools: Props['defaultTools'];\n toolOptions: Props['toolOptions'];\n /** `viewport.inertia`, which is the hand tool's. */\n inertia: NonNullable<Props['viewport']>['inertia'];\n ambient: Props['ambient'];\n /** `null` leaves out the kit's default actions, the marker drag among them. */\n actions: Props['actions'];\n /** `longPress.feedback`. Default true, which installs the kit's own. */\n pressFeedback: NonNullable<Props['longPress']>['feedback'];\n initialActiveTool: Props['initialActiveTool'];\n modes: Props['modes'];\n onToolsCreated: Props['onToolsCreated'];\n}): {\n /** What the canvas routes input through: the takeover, or `internal`. */\n tools: ToolsApi;\n /** The canvas's own api, built whether or not a takeover replaces it. */\n internal: ToolsApi;\n takeover: ToolsApi | null;\n} {\n const { select, enabled, tools: toolsProp, defaultTools, toolOptions, inertia, ambient, initialActiveTool, modes, onToolsCreated } = args;\n\n const takeover = toolsProp && isToolsApi(toolsProp) ? toolsProp : null;\n const registry = useBuiltinTools({\n select,\n enabled,\n defaultTools,\n patch: toolsProp && !isToolsApi(toolsProp) ? toolsProp : null,\n toolOptions,\n inertia,\n });\n\n const defaultPressFeedback = useMemo(() => createLongPressFeedbackContribution(), []);\n const feedbackOpt = args.pressFeedback ?? true;\n const pressFeedback = feedbackOpt === true ? defaultPressFeedback : feedbackOpt || null;\n const defaultMarkerDrag = useMemo(() => createViewMarkerContribution(), []);\n const markerDrag = args.actions === null ? null : defaultMarkerDrag;\n const mergedAmbient = useMemo(\n () => [\n ...presetContributions(enabled), ...(ambient ?? []),\n ...(pressFeedback ? [pressFeedback] : []), ...(markerDrag ? [markerDrag] : []),\n ],\n [enabled, ambient, pressFeedback, markerDrag],\n );\n\n const internal = useTools({\n active: initialActiveTool ?? ('select' in registry ? 'select' : null),\n registry,\n ...(mergedAmbient.length ? { ambient: mergedAmbient } : {}),\n ...(modes ? { modes } : {}),\n });\n const tools = takeover ?? internal;\n\n const onToolsCreatedRef = useLatest(onToolsCreated);\n useEffect(() => { onToolsCreatedRef.current?.(tools); }, [tools, onToolsCreatedRef]);\n\n return { tools, internal, takeover };\n}\n\n/**\n * The presets' ambient bindings, and the standard actions the canvas\n * registers. The bindings are not tools and sit outside `tools`, so they apply\n * under a takeover too. An action is registered when an enabled preset brings\n * it, or when it is in `pool` and a tool or contribution on this canvas binds\n * it: a tool brings the actions it routes to, so `defaultTools={['rect']}`\n * works under any preset.\n */\nexport function useFeatureBindings(args: {\n enabled: EnabledPresets;\n /** Actions registered only when something binds them. */\n pool: readonly Action[];\n tools: Pick<ToolsApi, 'registry' | 'ambient'>;\n move: FeatureBindingOptions['move'];\n rotate: FeatureBindingOptions['rotate'];\n}): { contributions: Contribution[]; standardActions: Action[] } {\n const { enabled, pool, tools, move, rotate } = args;\n const contributions = useMemo<Contribution[]>(\n () => presetAmbient(enabled, { move, rotate }),\n [enabled, move, rotate],\n );\n const standardActions = useMemo(() => {\n const out = presetActions(enabled);\n const have = new Set(out.map((a) => a.id));\n const bound = new Set<string>();\n for (const entry of [...Object.values(tools.registry), ...tools.ambient, ...contributions]) {\n for (const b of entry.bindings ?? []) bound.add(b.actionId);\n }\n for (const a of pool) {\n if (bound.has(a.id) && !have.has(a.id)) {\n have.add(a.id);\n out.push(a);\n }\n }\n return out;\n }, [enabled, pool, tools, contributions]);\n return { contributions, standardActions };\n}\n\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
- import { createNodeRouting } from "../../core/scene/NodeRouting.js";
2
1
  import { inferredNodeRouting } from "./defaultNodeRouting.js";
2
+ import { createNodeRouting } from "../../core/scene/NodeRouting.js";
3
3
  import { useMemo } from "react";
4
4
 
5
5
  //#region src/canvas/SceneCanvas/useNodeKinds.ts
@@ -1 +1 @@
1
- {"version":3,"file":"useNodeKinds.js","names":[],"sources":["../../../src/canvas/SceneCanvas/useNodeKinds.ts"],"sourcesContent":["import { useMemo } from 'react';\nimport { createNodeRouting, type NodeRoutingEntry } from 'core/scene/NodeRouting';\nimport type { NodeId, Scene } from 'core/scene/types';\nimport { inferredNodeRouting } from './defaultNodeRouting';\n\n/**\n * The canvas's routing-trait classifier, by node data and by node id, so\n * `target: 'kind:text'` on a binding speaks the vocabulary of `Hit.kind`.\n * Unset `routing` falls back to `inferredNodeRouting`. An explicit empty list\n * opts out: both are undefined, every hit is `kind: 'unknown'`, and no\n * `kind:` target form can match.\n */\nexport function useNodeKinds<TData, TLayer extends string, TPose>(\n scene: Scene<TData, TLayer, TPose>,\n routing: readonly NodeRoutingEntry[] | undefined,\n): {\n kindOf: ((node: { kind: string; data: TData }) => string) | undefined;\n kindOfNode: ((id: string) => string | undefined) | undefined;\n} {\n const kindOf = useMemo(() => {\n const effective = routing === undefined ? inferredNodeRouting : routing;\n if (effective.length === 0) return undefined;\n const registry = createNodeRouting();\n for (const k of effective) registry.register(k);\n return (node: { kind: string; data: TData }) => registry.classify(node.data, node);\n }, [routing]);\n\n const kindOfNode = useMemo(() => {\n if (!kindOf) return undefined;\n return (id: string): string | undefined => {\n const node = scene.get(id as NodeId);\n return node ? kindOf(node) : undefined;\n };\n }, [kindOf, scene]);\n\n return { kindOf, kindOfNode };\n}\n"],"mappings":";;;;;;;;;;;;AAYA,SAAgB,aACd,OACA,SAIA;CACA,MAAM,SAAS,cAAc;EAC3B,MAAM,YAAY,YAAY,SAAY,sBAAsB;EAChE,IAAI,UAAU,WAAW,GAAG,OAAO;EACnC,MAAM,WAAW,kBAAkB;EACnC,KAAK,MAAM,KAAK,WAAW,SAAS,SAAS,CAAC;EAC9C,QAAQ,SAAwC,SAAS,SAAS,KAAK,MAAM,IAAI;CACnF,GAAG,CAAC,OAAO,CAAC;CAUZ,OAAO;EAAE;EAAQ,YARE,cAAc;GAC/B,IAAI,CAAC,QAAQ,OAAO;GACpB,QAAQ,OAAmC;IACzC,MAAM,OAAO,MAAM,IAAI,EAAY;IACnC,OAAO,OAAO,OAAO,IAAI,IAAI;GAC/B;EACF,GAAG,CAAC,QAAQ,KAAK,CAEA;CAAW;AAC9B"}
1
+ {"version":3,"file":"useNodeKinds.js","names":[],"sources":["../../../src/canvas/SceneCanvas/useNodeKinds.ts"],"sourcesContent":["import { useMemo } from 'react';\nimport { createNodeRouting, type NodeRoutingEntry } from 'core/scene/NodeRouting';\nimport type { NodeId, Scene } from 'core/scene/types';\nimport { inferredNodeRouting } from './defaultNodeRouting';\n\nexport interface NodeKinds<TData> {\n kindOf: ((node: { kind: string; data: TData }) => string) | undefined;\n kindOfNode: ((id: string) => string | undefined) | undefined;\n}\n\n/**\n * The canvas's routing-trait classifier, by node data and by node id, so\n * `target: 'kind:text'` on a binding speaks the vocabulary of `Hit.kind`.\n * Unset `routing` falls back to `inferredNodeRouting`. An explicit empty list\n * opts out: both are undefined, every hit is `kind: 'unknown'`, and no\n * `kind:` target form can match.\n */\nexport function useNodeKinds<TData, TLayer extends string, TPose>(\n scene: Scene<TData, TLayer, TPose>,\n routing: readonly NodeRoutingEntry[] | undefined,\n): NodeKinds<TData> {\n const kindOf = useMemo(() => {\n const effective = routing === undefined ? inferredNodeRouting : routing;\n if (effective.length === 0) return undefined;\n const registry = createNodeRouting();\n for (const k of effective) registry.register(k);\n return (node: { kind: string; data: TData }) => registry.classify(node.data, node);\n }, [routing]);\n\n const kindOfNode = useMemo(() => {\n if (!kindOf) return undefined;\n return (id: string): string | undefined => {\n const node = scene.get(id as NodeId);\n return node ? kindOf(node) : undefined;\n };\n }, [kindOf, scene]);\n\n return { kindOf, kindOfNode };\n}\n"],"mappings":";;;;;;;;;;;;AAiBA,SAAgB,aACd,OACA,SACkB;CAClB,MAAM,SAAS,cAAc;EAC3B,MAAM,YAAY,YAAY,SAAY,sBAAsB;EAChE,IAAI,UAAU,WAAW,GAAG,OAAO;EACnC,MAAM,WAAW,kBAAkB;EACnC,KAAK,MAAM,KAAK,WAAW,SAAS,SAAS,CAAC;EAC9C,QAAQ,SAAwC,SAAS,SAAS,KAAK,MAAM,IAAI;CACnF,GAAG,CAAC,OAAO,CAAC;CAUZ,OAAO;EAAE;EAAQ,YARE,cAAc;GAC/B,IAAI,CAAC,QAAQ,OAAO;GACpB,QAAQ,OAAmC;IACzC,MAAM,OAAO,MAAM,IAAI,EAAY;IACnC,OAAO,OAAO,OAAO,IAAI,IAAI;GAC/B;EACF,GAAG,CAAC,QAAQ,KAAK,CAEA;CAAW;AAC9B"}
@@ -26,7 +26,9 @@ function useAddedViews() {
26
26
  w: 0,
27
27
  h: 0
28
28
  }
29
- }, [surfaceViewRegistry])
29
+ }, [surfaceViewRegistry]),
30
+ aimOf: useCallback((id) => surfaceViewRegistry?.aimOf(id) ?? null, [surfaceViewRegistry]),
31
+ setAim: useCallback((id, aim) => surfaceViewRegistry?.setAim(id, aim) ?? false, [surfaceViewRegistry])
30
32
  };
31
33
  }
32
34
  /**
@@ -35,7 +37,7 @@ function useAddedViews() {
35
37
  * and keeps the canvas's own copies of the element and the handle current.
36
38
  */
37
39
  function useSceneCanvasHandle(args) {
38
- const { ref, elementRef, apiRef, onElement, ingest, viewAnimation, camera, addView, viewAt } = args;
40
+ const { ref, elementRef, apiRef, onElement, ingest, viewAnimation, camera, addView, viewAt, aimOf, setAim } = args;
39
41
  const [ready, setReady] = useState(false);
40
42
  return {
41
43
  handleRef: useCallback((node) => {
@@ -49,7 +51,9 @@ function useSceneCanvasHandle(args) {
49
51
  isViewAnimating: viewAnimation.isAnimating,
50
52
  camera,
51
53
  addView,
52
- viewAt
54
+ viewAt,
55
+ aimOf,
56
+ setAim
53
57
  } : null;
54
58
  apiRef.current = extended;
55
59
  setReady(extended !== null);
@@ -63,6 +67,8 @@ function useSceneCanvasHandle(args) {
63
67
  camera,
64
68
  addView,
65
69
  viewAt,
70
+ aimOf,
71
+ setAim,
66
72
  onElement
67
73
  ]),
68
74
  ready
@@ -1 +1 @@
1
- {"version":3,"file":"useSceneCanvasHandle.js","names":[],"sources":["../../../src/canvas/SceneCanvas/useSceneCanvasHandle.ts"],"sourcesContent":["import { useCallback, useState, type ForwardedRef, type MutableRefObject } from 'react';\nimport { assignRef } from '@weasel-js/react';\nimport type { ViewAnimationApi } from 'core/viewport/useViewAnimation';\nimport type { CanvasViewProps } from '../CanvasView';\nimport type { CanvasExtensionApi, CanvasViewHandle, SceneCanvasApi } from '../canvasExtension';\nimport { IDENTITY_VIEW, useOptionalViewRegistry } from '../viewRegistry';\n\n/** Views added through the handle rather than declared as props or children. */\nexport function useAddedViews(): {\n views: readonly CanvasViewProps[];\n addView: SceneCanvasApi['addView'];\n viewAt: SceneCanvasApi['viewAt'];\n} {\n const surfaceViewRegistry = useOptionalViewRegistry();\n const [views, setViews] = useState<readonly CanvasViewProps[]>([]);\n const addView = useCallback((props: CanvasViewProps): CanvasViewHandle => {\n setViews((list) => [...list.filter((v) => v.id !== props.id), props]);\n return {\n id: props.id,\n draw: (data, outer, dims) =>\n surfaceViewRegistry?.list().find((r) => r.id === props.id)?.layer.draw(data, outer, dims) ?? [],\n remove: () => setViews((list) => list.filter((v) => v !== props)),\n };\n }, [surfaceViewRegistry]);\n const viewAt = useCallback<SceneCanvasApi['viewAt']>((at, opts) => (\n surfaceViewRegistry?.viewAt(at, opts) ?? { id: null, view: IDENTITY_VIEW, rect: { x: 0, y: 0, w: 0, h: 0 } }\n ), [surfaceViewRegistry]);\n return { views, addView, viewAt };\n}\n\n/**\n * The ref callback `<SceneCanvas>` hands `<Canvas>`. It extends the\n * primitive's handle into the `SceneCanvasApi` the consumer's ref receives,\n * and keeps the canvas's own copies of the element and the handle current.\n */\nexport function useSceneCanvasHandle(args: {\n ref: ForwardedRef<SceneCanvasApi>;\n /** Written with the canvas element, for the input listeners. */\n elementRef: MutableRefObject<HTMLElement | null>;\n /** Written with the extended handle, for `requestRedraw` and point conversion. */\n apiRef: MutableRefObject<CanvasExtensionApi | null>;\n /** Told the element whenever it attaches or detaches. */\n onElement: (element: HTMLElement | null) => void;\n ingest: SceneCanvasApi['ingest'];\n viewAnimation: Pick<ViewAnimationApi, 'animate' | 'stop' | 'isAnimating'>;\n camera: SceneCanvasApi['camera'];\n addView: SceneCanvasApi['addView'];\n viewAt: SceneCanvasApi['viewAt'];\n}): {\n handleRef: (node: CanvasExtensionApi | null) => void;\n /** Whether the handle is attached, as state: an effect needing the handle\n * keys off this instead of assuming when React attaches it. */\n ready: boolean;\n} {\n const { ref, elementRef, apiRef, onElement, ingest, viewAnimation, camera, addView, viewAt } = args;\n const [ready, setReady] = useState(false);\n const handleRef = useCallback(\n (node: CanvasExtensionApi | null) => {\n elementRef.current = node?.element ?? null;\n onElement(elementRef.current);\n const extended: SceneCanvasApi | null = node\n ? {\n ...node,\n ingest,\n animateView: viewAnimation.animate,\n stopViewAnimation: viewAnimation.stop,\n isViewAnimating: viewAnimation.isAnimating,\n camera,\n addView,\n viewAt,\n }\n : null;\n apiRef.current = extended;\n setReady(extended !== null);\n assignRef(ref, extended);\n },\n [ref, elementRef, apiRef, ingest, viewAnimation, camera, addView, viewAt, onElement],\n );\n return { handleRef, ready };\n}\n"],"mappings":";;;;;;AAQA,SAAgB,gBAId;CACA,MAAM,sBAAsB,wBAAwB;CACpD,MAAM,CAAC,OAAO,YAAY,SAAqC,CAAC,CAAC;CAajE,OAAO;EAAE;EAAO,SAZA,aAAa,UAA6C;GACxE,UAAU,SAAS,CAAC,GAAG,KAAK,QAAQ,MAAM,EAAE,OAAO,MAAM,EAAE,GAAG,KAAK,CAAC;GACpE,OAAO;IACL,IAAI,MAAM;IACV,OAAO,MAAM,OAAO,SAClB,qBAAqB,KAAK,CAAC,CAAC,MAAM,MAAM,EAAE,OAAO,MAAM,EAAE,CAAC,EAAE,MAAM,KAAK,MAAM,OAAO,IAAI,KAAK,CAAC;IAChG,cAAc,UAAU,SAAS,KAAK,QAAQ,MAAM,MAAM,KAAK,CAAC;GAClE;EACF,GAAG,CAAC,mBAAmB,CAIP;EAAS,QAHV,aAAuC,IAAI,SACxD,qBAAqB,OAAO,IAAI,IAAI,KAAK;GAAE,IAAI;GAAM,MAAM;GAAe,MAAM;IAAE,GAAG;IAAG,GAAG;IAAG,GAAG;IAAG,GAAG;GAAE;EAAE,GAC1G,CAAC,mBAAmB,CACE;CAAO;AAClC;;;;;;AAOA,SAAgB,qBAAqB,MAkBnC;CACA,MAAM,EAAE,KAAK,YAAY,QAAQ,WAAW,QAAQ,eAAe,QAAQ,SAAS,WAAW;CAC/F,MAAM,CAAC,OAAO,YAAY,SAAS,KAAK;CAuBxC,OAAO;EAAE,WAtBS,aACf,SAAoC;GACnC,WAAW,UAAU,MAAM,WAAW;GACtC,UAAU,WAAW,OAAO;GAC5B,MAAM,WAAkC,OACpC;IACE,GAAG;IACH;IACA,aAAa,cAAc;IAC3B,mBAAmB,cAAc;IACjC,iBAAiB,cAAc;IAC/B;IACA;IACA;GACF,IACA;GACJ,OAAO,UAAU;GACjB,SAAS,aAAa,IAAI;GAC1B,UAAU,KAAK,QAAQ;EACzB,GACA;GAAC;GAAK;GAAY;GAAQ;GAAQ;GAAe;GAAQ;GAAS;GAAQ;EAAS,CAE5E;EAAW;CAAM;AAC5B"}
1
+ {"version":3,"file":"useSceneCanvasHandle.js","names":[],"sources":["../../../src/canvas/SceneCanvas/useSceneCanvasHandle.ts"],"sourcesContent":["import { useCallback, useState, type ForwardedRef, type MutableRefObject } from 'react';\nimport { assignRef } from '@weasel-js/react';\nimport type { ViewAnimationApi } from 'core/viewport/useViewAnimation';\nimport type { CanvasViewProps } from '../CanvasView';\nimport type { CanvasExtensionApi, CanvasViewHandle, SceneCanvasApi } from '../canvasExtension';\nimport { IDENTITY_VIEW, useOptionalViewRegistry } from '../viewRegistry';\n\n/** Views added through the handle rather than declared as props or children. */\nexport function useAddedViews(): {\n views: readonly CanvasViewProps[];\n addView: SceneCanvasApi['addView'];\n viewAt: SceneCanvasApi['viewAt'];\n aimOf: SceneCanvasApi['aimOf'];\n setAim: SceneCanvasApi['setAim'];\n} {\n const surfaceViewRegistry = useOptionalViewRegistry();\n const [views, setViews] = useState<readonly CanvasViewProps[]>([]);\n const addView = useCallback((props: CanvasViewProps): CanvasViewHandle => {\n setViews((list) => [...list.filter((v) => v.id !== props.id), props]);\n return {\n id: props.id,\n draw: (data, outer, dims) =>\n surfaceViewRegistry?.list().find((r) => r.id === props.id)?.layer.draw(data, outer, dims) ?? [],\n remove: () => setViews((list) => list.filter((v) => v !== props)),\n };\n }, [surfaceViewRegistry]);\n const viewAt = useCallback<SceneCanvasApi['viewAt']>((at, opts) => (\n surfaceViewRegistry?.viewAt(at, opts) ?? { id: null, view: IDENTITY_VIEW, rect: { x: 0, y: 0, w: 0, h: 0 } }\n ), [surfaceViewRegistry]);\n const aimOf = useCallback<SceneCanvasApi['aimOf']>(\n (id) => surfaceViewRegistry?.aimOf(id) ?? null, [surfaceViewRegistry]);\n const setAim = useCallback<SceneCanvasApi['setAim']>(\n (id, aim) => surfaceViewRegistry?.setAim(id, aim) ?? false, [surfaceViewRegistry]);\n return { views, addView, viewAt, aimOf, setAim };\n}\n\n/**\n * The ref callback `<SceneCanvas>` hands `<Canvas>`. It extends the\n * primitive's handle into the `SceneCanvasApi` the consumer's ref receives,\n * and keeps the canvas's own copies of the element and the handle current.\n */\nexport function useSceneCanvasHandle(args: {\n ref: ForwardedRef<SceneCanvasApi>;\n /** Written with the canvas element, for the input listeners. */\n elementRef: MutableRefObject<HTMLElement | null>;\n /** Written with the extended handle, for `requestRedraw` and point conversion. */\n apiRef: MutableRefObject<CanvasExtensionApi | null>;\n /** Told the element whenever it attaches or detaches. */\n onElement: (element: HTMLElement | null) => void;\n ingest: SceneCanvasApi['ingest'];\n viewAnimation: Pick<ViewAnimationApi, 'animate' | 'stop' | 'isAnimating'>;\n camera: SceneCanvasApi['camera'];\n addView: SceneCanvasApi['addView'];\n viewAt: SceneCanvasApi['viewAt'];\n aimOf: SceneCanvasApi['aimOf'];\n setAim: SceneCanvasApi['setAim'];\n}): {\n handleRef: (node: CanvasExtensionApi | null) => void;\n /** Whether the handle is attached, as state: an effect needing the handle\n * keys off this instead of assuming when React attaches it. */\n ready: boolean;\n} {\n const { ref, elementRef, apiRef, onElement, ingest, viewAnimation, camera, addView, viewAt, aimOf, setAim } = args;\n const [ready, setReady] = useState(false);\n const handleRef = useCallback(\n (node: CanvasExtensionApi | null) => {\n elementRef.current = node?.element ?? null;\n onElement(elementRef.current);\n const extended: SceneCanvasApi | null = node\n ? {\n ...node,\n ingest,\n animateView: viewAnimation.animate,\n stopViewAnimation: viewAnimation.stop,\n isViewAnimating: viewAnimation.isAnimating,\n camera,\n addView,\n viewAt,\n aimOf,\n setAim,\n }\n : null;\n apiRef.current = extended;\n setReady(extended !== null);\n assignRef(ref, extended);\n },\n [ref, elementRef, apiRef, ingest, viewAnimation, camera, addView, viewAt, aimOf, setAim, onElement],\n );\n return { handleRef, ready };\n}\n"],"mappings":";;;;;;AAQA,SAAgB,gBAMd;CACA,MAAM,sBAAsB,wBAAwB;CACpD,MAAM,CAAC,OAAO,YAAY,SAAqC,CAAC,CAAC;CAiBjE,OAAO;EAAE;EAAO,SAhBA,aAAa,UAA6C;GACxE,UAAU,SAAS,CAAC,GAAG,KAAK,QAAQ,MAAM,EAAE,OAAO,MAAM,EAAE,GAAG,KAAK,CAAC;GACpE,OAAO;IACL,IAAI,MAAM;IACV,OAAO,MAAM,OAAO,SAClB,qBAAqB,KAAK,CAAC,CAAC,MAAM,MAAM,EAAE,OAAO,MAAM,EAAE,CAAC,EAAE,MAAM,KAAK,MAAM,OAAO,IAAI,KAAK,CAAC;IAChG,cAAc,UAAU,SAAS,KAAK,QAAQ,MAAM,MAAM,KAAK,CAAC;GAClE;EACF,GAAG,CAAC,mBAAmB,CAQP;EAAS,QAPV,aAAuC,IAAI,SACxD,qBAAqB,OAAO,IAAI,IAAI,KAAK;GAAE,IAAI;GAAM,MAAM;GAAe,MAAM;IAAE,GAAG;IAAG,GAAG;IAAG,GAAG;IAAG,GAAG;GAAE;EAAE,GAC1G,CAAC,mBAAmB,CAKE;EAAQ,OAJnB,aACX,OAAO,qBAAqB,MAAM,EAAE,KAAK,MAAM,CAAC,mBAAmB,CAGrC;EAAO,QAFzB,aACZ,IAAI,QAAQ,qBAAqB,OAAO,IAAI,GAAG,KAAK,OAAO,CAAC,mBAAmB,CAC1C;CAAO;AACjD;;;;;;AAOA,SAAgB,qBAAqB,MAoBnC;CACA,MAAM,EAAE,KAAK,YAAY,QAAQ,WAAW,QAAQ,eAAe,QAAQ,SAAS,QAAQ,OAAO,WAAW;CAC9G,MAAM,CAAC,OAAO,YAAY,SAAS,KAAK;CAyBxC,OAAO;EAAE,WAxBS,aACf,SAAoC;GACnC,WAAW,UAAU,MAAM,WAAW;GACtC,UAAU,WAAW,OAAO;GAC5B,MAAM,WAAkC,OACpC;IACE,GAAG;IACH;IACA,aAAa,cAAc;IAC3B,mBAAmB,cAAc;IACjC,iBAAiB,cAAc;IAC/B;IACA;IACA;IACA;IACA;GACF,IACA;GACJ,OAAO,UAAU;GACjB,SAAS,aAAa,IAAI;GAC1B,UAAU,KAAK,QAAQ;EACzB,GACA;GAAC;GAAK;GAAY;GAAQ;GAAQ;GAAe;GAAQ;GAAS;GAAQ;GAAO;GAAQ;EAAS,CAE3F;EAAW;CAAM;AAC5B"}
@@ -1,4 +1,5 @@
1
1
  import { targetSizesPx } from "../../core/device/targets.js";
2
+ import { drawnBoundsScene } from "../derivedPath.js";
2
3
  import { createSnapOutcomeStore } from "../../features/snap/outcomeStore.js";
3
4
  import { builtLayersOf, isCustomEntry } from "../layerSlots.js";
4
5
  import { useTargetBasePx } from "../../core/device/useTargetBasePx.js";
@@ -8,6 +9,7 @@ import { mergeLayersWithDefaults } from "./mergeLayers.js";
8
9
  import { useDispatcherOverlayLayer } from "./useDispatcherOverlayLayer.js";
9
10
  import { usePreviewGhostLayer } from "./usePreviewGhostLayer.js";
10
11
  import { useDepartureGhostLayer } from "./useDepartureGhostLayer.js";
12
+ import { useEffectSourcesLayer } from "../../features/pathEffects/useEffectSourcesLayer.js";
11
13
  import { usePoseTransition } from "../../animation/poseTransition.js";
12
14
  import { useSceneSlotLayers } from "./useSceneSlotLayers.js";
13
15
  import { useSelectionOverlayLayer } from "./useSelectionOverlayLayer.js";
@@ -19,7 +21,8 @@ import { useMemo, useRef, useState } from "react";
19
21
  * The layer map `<SceneCanvas>` hands `<Canvas>`: the caller's `layers` over
20
22
  * the kit defaults, with the scene and selection-overlay slots built, and the
21
23
  * canvas's own layers anchored around them. Removed nodes leave just above
22
- * the scene, the preview ghost above them, the dispatcher's overlay (marquee, lasso) above the ghost, and the
24
+ * the scene, the preview ghost above them, a selected path effect's hidden sources above that, the dispatcher's
25
+ * overlay (marquee, lasso) above those, and the
23
26
  * anchor overlay above the selection chrome.
24
27
  */
25
28
  function useSceneCanvasLayers(args) {
@@ -50,6 +53,7 @@ function useSceneCanvasLayers(args) {
50
53
  sceneSlot,
51
54
  departures
52
55
  });
56
+ const effectSourcesLayer = useEffectSourcesLayer(scene);
53
57
  const dispatcherOverlay = useDispatcherOverlayLayer({ dispatcher });
54
58
  const hitRadiusPx = args.selectTool?.handleHitRadius ?? targetSizesPx(targetScale, baseSizes).handle;
55
59
  const edges = args.selectTool?.resize?.edgeHandles ?? true;
@@ -60,7 +64,17 @@ function useSceneCanvasLayers(args) {
60
64
  const chromeAffordancesRef = useRef([]);
61
65
  const slopsLayer = useMemo(() => createSlopsDebugLayer({ getAffordances: () => chromeAffordancesRef.current }), []);
62
66
  const [snapStore] = useState(() => createSnapOutcomeStore());
63
- const snapReadoutLayer = useMemo(() => createSnapReadoutLayer(snapStore, args.snapReadoutStyle), [snapStore, args.snapReadoutStyle]);
67
+ const { color, gapColor, lineWidth } = args.snapReadoutStyle ?? {};
68
+ const snapReadoutLayer = useMemo(() => createSnapReadoutLayer(snapStore, {
69
+ ...color !== void 0 ? { color } : {},
70
+ ...gapColor !== void 0 ? { gapColor } : {},
71
+ ...lineWidth !== void 0 ? { lineWidth } : {}
72
+ }), [
73
+ snapStore,
74
+ color,
75
+ gapColor,
76
+ lineWidth
77
+ ]);
64
78
  const overlaySlot = merged.pathEditingOverlay;
65
79
  const overlayConfig = overlaySlot && !isCustomEntry(overlaySlot) ? overlaySlot : void 0;
66
80
  const overlayAnchor = overlaySlot === null ? "dispatcherOverlay" : "pathEditingOverlay";
@@ -68,7 +82,7 @@ function useSceneCanvasLayers(args) {
68
82
  nodeOf: (id) => scene.get(id),
69
83
  planeOfNode: args.planeOfNode
70
84
  }, overlayConfig);
71
- const { layer: selectionOverlayLayer, rotationBadge } = useSelectionOverlayLayer(merged.selectionOverlay, pathEditState.getEditingIds, poseDescriptor, args.boundsIncludeStroke ? scene : void 0, resizeHandles);
85
+ const { layer: selectionOverlayLayer, rotationBadge } = useSelectionOverlayLayer(merged.selectionOverlay, pathEditState.getEditingIds, poseDescriptor, args.boundsIncludeStroke ? drawnBoundsScene(scene) : void 0, resizeHandles);
72
86
  return {
73
87
  layers: useMemo(() => ({
74
88
  ...builtLayersOf(merged),
@@ -82,9 +96,13 @@ function useSceneCanvasLayers(args) {
82
96
  layer: previewLayer,
83
97
  after: "departureGhost"
84
98
  },
99
+ effectSources: {
100
+ layer: effectSourcesLayer,
101
+ after: "previewGhost"
102
+ },
85
103
  dispatcherOverlay: {
86
104
  layer: dispatcherOverlay,
87
- after: "previewGhost"
105
+ after: "effectSources"
88
106
  },
89
107
  pathEditingOverlay: overlaySlot === null || isCustomEntry(overlaySlot) ? overlaySlot : {
90
108
  layer: pathEditingOverlayLayer,
@@ -104,6 +122,7 @@ function useSceneCanvasLayers(args) {
104
122
  selectionOverlayLayer,
105
123
  departureLayer,
106
124
  previewLayer,
125
+ effectSourcesLayer,
107
126
  dispatcherOverlay,
108
127
  pathEditingOverlayLayer,
109
128
  overlaySlot,
@@ -1 +1 @@
1
- {"version":3,"file":"useSceneCanvasLayers.js","names":[],"sources":["../../../src/canvas/SceneCanvas/useSceneCanvasLayers.ts"],"sourcesContent":["import { useMemo, useRef, useState, type MutableRefObject } from 'react';\nimport type { ColorOverrideRegistry } from '@weasel-js/animator';\nimport type { Dispatcher } from '@weasel-js/routing';\nimport type { Affordance } from 'affordances/types';\nimport type { Node, NodeId, Scene } from 'core/scene/types';\nimport type { Bounds } from 'core/viewport/fitViewToBounds';\nimport type { PlaneMap } from 'core/viewport/parallax';\nimport type { View } from 'core/viewport/view';\nimport type { PathEditState } from 'features/paths/pathEditState';\nimport { usePathEditOverlayLayer } from 'features/paths/usePathEdit';\nimport type { rotationBadgeOf } from 'features/selection/overlay';\nimport type { PoseDescriptor } from 'interactions/actions/resize/geometry';\nimport type { HierarchicalAdapter } from '../buildSceneTree';\nimport { builtLayersOf, isCustomEntry, type CanvasLayers } from '../layerSlots';\nimport { createSlopsDebugLayer } from '../slopsDebugLayer';\nimport { useTargetBasePx } from 'core/device/useTargetBasePx';\nimport { targetSizesPx } from 'core/device/targets';\nimport type { ResizeHandleLayout } from 'interactions/actions/resize/cornerHandles';\nimport { mergeLayersWithDefaults } from './mergeLayers';\nimport type { SceneCanvasLayers } from './props';\nimport { useDispatcherOverlayLayer } from './useDispatcherOverlayLayer';\nimport { usePreviewGhostLayer } from './usePreviewGhostLayer';\nimport { useDepartureGhostLayer } from './useDepartureGhostLayer';\nimport type { Departures } from '../../animation/departures';\nimport { usePoseTransition, type PoseTransitionSeat } from '../../animation/poseTransition';\nimport { useSceneSlotLayers } from './useSceneSlotLayers';\nimport { useSelectionOverlayLayer } from './useSelectionOverlayLayer';\nimport type { DrawnBoundsScene } from '../drawnBounds';\nimport { createSnapOutcomeStore, type SnapOutcomeStore } from 'features/snap/outcomeStore';\nimport { createSnapReadoutLayer, type SnapReadoutStyle } from 'features/snap/readoutLayer';\n\n/**\n * The layer map `<SceneCanvas>` hands `<Canvas>`: the caller's `layers` over\n * the kit defaults, with the scene and selection-overlay slots built, and the\n * canvas's own layers anchored around them. Removed nodes leave just above\n * the scene, the preview ghost above them, the dispatcher's overlay (marquee, lasso) above the ghost, and the\n * anchor overlay above the selection chrome.\n */\nexport function useSceneCanvasLayers<TData, TLayer extends string, TPose>(args: {\n /** `<SceneCanvas layers>`. Omitted, the result is the full default set. */\n layers: SceneCanvasLayers<Node<TData, TLayer, TPose>, TPose> | undefined;\n /** The device profile's, which sizes the default handles. */\n targetScale: number;\n scene: Scene<TData, TLayer, TPose>;\n adapter: HierarchicalAdapter<Node<TData, TLayer, TPose>, TPose>;\n poseDescriptor: PoseDescriptor<TPose>;\n alphaFor: ((id: string) => number) | undefined;\n colorOverrides: ColorOverrideRegistry | undefined;\n boundsOf: (id: string) => Bounds | null;\n planeOfNode: (id: string, view: View) => PlaneMap | null;\n /** `<SceneCanvas poseTransition>`, whose ghosts of removed nodes this draws. */\n poseTransition: PoseTransitionSeat<TPose> | null | undefined;\n /** Ids an in-flight gesture is ghosting. */\n previewIds: () => Iterable<string> | null;\n dispatcher: Dispatcher;\n /** Whether to mount the snap readout layer. */\n snapReadout: boolean;\n snapReadoutStyle?: SnapReadoutStyle;\n pathEditState: PathEditState;\n /** `debug.slops`: paint the hit regions of the chrome affordances. */\n slops: boolean;\n /** `geometry.boundsIncludeStroke`: whether chrome sits on the stroke. */\n boundsIncludeStroke: boolean;\n /** `selectTool`'s `handleHitRadius` and `resize.edgeHandles`, resolved here into\n * the one {@link ResizeHandleLayout} the overlay paints and the hit-test reads. */\n selectTool?: { handleHitRadius?: number; resize?: { edgeHandles?: boolean } };\n}): {\n layers: CanvasLayers;\n /** Where the selection overlay paints its rotate badge, or null. */\n rotationBadge: ReturnType<typeof rotationBadgeOf>;\n /** Which resize handles exist and their hit radius, for every hit-test of this canvas. */\n resizeHandles: ResizeHandleLayout;\n /** The affordances the gesture mounter hit-tests, which it publishes here\n * so the slops halos are the hit regions rather than a copy of them. */\n chromeAffordancesRef: MutableRefObject<readonly Affordance[]>;\n /** The marks the readout layer draws; the canvas's snap dep writes them. */\n snapStore: SnapOutcomeStore;\n /** The removed nodes the seat is seeing off. */\n departures: Departures<TPose, Node<TData, TLayer, TPose>>;\n} {\n const { scene, adapter, poseDescriptor, alphaFor, dispatcher, pathEditState, slops, targetScale } = args;\n\n const baseSizes = useTargetBasePx();\n const merged = useMemo(\n () => mergeLayersWithDefaults(args.layers, targetScale, baseSizes),\n [args.layers, targetScale, baseSizes],\n );\n\n const { config: sceneSlot, layers: sceneLayers } = useSceneSlotLayers({\n slot: merged.scene,\n scene,\n adapter,\n alphaFor,\n colorOverrides: args.colorOverrides,\n boundsOf: args.boundsOf,\n previewIds: args.previewIds,\n });\n // Takes the scene-wired slot, so a ghosted derived node still resolves its path.\n const previewLayer = usePreviewGhostLayer<TData, TLayer, TPose>({ scene, sceneSlot, dispatcher });\n const departures = usePoseTransition(scene, args.poseTransition);\n const departureLayer = useDepartureGhostLayer({ scene, sceneSlot, departures });\n const dispatcherOverlay = useDispatcherOverlayLayer({ dispatcher });\n\n const hitRadiusPx = args.selectTool?.handleHitRadius ?? targetSizesPx(targetScale, baseSizes).handle;\n const edges = args.selectTool?.resize?.edgeHandles ?? true;\n const resizeHandles = useMemo<ResizeHandleLayout>(() => ({ edges, hitRadiusPx }), [edges, hitRadiusPx]);\n\n const chromeAffordancesRef = useRef<readonly Affordance[]>([]);\n const slopsLayer = useMemo(\n () => createSlopsDebugLayer({ getAffordances: () => chromeAffordancesRef.current }),\n [],\n );\n\n const [snapStore] = useState(() => createSnapOutcomeStore());\n const snapReadoutLayer = useMemo(() => createSnapReadoutLayer(snapStore, args.snapReadoutStyle), [snapStore, args.snapReadoutStyle]);\n const overlaySlot = merged.pathEditingOverlay;\n const overlayConfig = overlaySlot && !isCustomEntry(overlaySlot) ? overlaySlot : undefined;\n const overlayAnchor = overlaySlot === null ? 'dispatcherOverlay' : 'pathEditingOverlay';\n const pathEditingOverlayLayer = usePathEditOverlayLayer(pathEditState, {\n nodeOf: (id) => scene.get(id as NodeId),\n planeOfNode: args.planeOfNode,\n }, overlayConfig);\n\n const { layer: selectionOverlayLayer, rotationBadge } = useSelectionOverlayLayer<TPose>(\n merged.selectionOverlay,\n pathEditState.getEditingIds,\n poseDescriptor,\n args.boundsIncludeStroke ? (scene as unknown as DrawnBoundsScene) : undefined,\n resizeHandles,\n );\n\n const layers = useMemo<CanvasLayers>(() => ({\n ...builtLayersOf(merged),\n scene: sceneLayers,\n selectionOverlay: selectionOverlayLayer ? { layer: selectionOverlayLayer } : null,\n departureGhost: { layer: departureLayer, after: 'scene' },\n previewGhost: { layer: previewLayer, after: 'departureGhost' },\n dispatcherOverlay: { layer: dispatcherOverlay, after: 'previewGhost' },\n pathEditingOverlay: overlaySlot === null || isCustomEntry(overlaySlot)\n ? overlaySlot\n : { layer: pathEditingOverlayLayer, after: 'selectionOverlay' },\n ...(args.snapReadout ? { snapReadout: { layer: snapReadoutLayer, after: overlayAnchor } } : {}),\n ...(slops ? { slopsDebug: { layer: slopsLayer, after: args.snapReadout ? 'snapReadout' : overlayAnchor } } : {}),\n }), [\n merged, sceneLayers, selectionOverlayLayer, departureLayer, previewLayer, dispatcherOverlay, pathEditingOverlayLayer, overlaySlot, overlayAnchor,\n snapReadoutLayer, args.snapReadout, slops, slopsLayer,\n ]);\n\n return { layers, rotationBadge, resizeHandles, chromeAffordancesRef, snapStore, departures };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAsCA,SAAgB,qBAA0D,MAyCxE;CACA,MAAM,EAAE,OAAO,SAAS,gBAAgB,UAAU,YAAY,eAAe,OAAO,gBAAgB;CAEpG,MAAM,YAAY,gBAAgB;CAClC,MAAM,SAAS,cACP,wBAAwB,KAAK,QAAQ,aAAa,SAAS,GACjE;EAAC,KAAK;EAAQ;EAAa;CAAS,CACtC;CAEA,MAAM,EAAE,QAAQ,WAAW,QAAQ,gBAAgB,mBAAmB;EACpE,MAAM,OAAO;EACb;EACA;EACA;EACA,gBAAgB,KAAK;EACrB,UAAU,KAAK;EACf,YAAY,KAAK;CACnB,CAAC;CAED,MAAM,eAAe,qBAA2C;EAAE;EAAO;EAAW;CAAW,CAAC;CAChG,MAAM,aAAa,kBAAkB,OAAO,KAAK,cAAc;CAC/D,MAAM,iBAAiB,uBAAuB;EAAE;EAAO;EAAW;CAAW,CAAC;CAC9E,MAAM,oBAAoB,0BAA0B,EAAE,WAAW,CAAC;CAElE,MAAM,cAAc,KAAK,YAAY,mBAAmB,cAAc,aAAa,SAAS,CAAC,CAAC;CAC9F,MAAM,QAAQ,KAAK,YAAY,QAAQ,eAAe;CACtD,MAAM,gBAAgB,eAAmC;EAAE;EAAO;CAAY,IAAI,CAAC,OAAO,WAAW,CAAC;CAEtG,MAAM,uBAAuB,OAA8B,CAAC,CAAC;CAC7D,MAAM,aAAa,cACX,sBAAsB,EAAE,sBAAsB,qBAAqB,QAAQ,CAAC,GAClF,CAAC,CACH;CAEA,MAAM,CAAC,aAAa,eAAe,uBAAuB,CAAC;CAC3D,MAAM,mBAAmB,cAAc,uBAAuB,WAAW,KAAK,gBAAgB,GAAG,CAAC,WAAW,KAAK,gBAAgB,CAAC;CACnI,MAAM,cAAc,OAAO;CAC3B,MAAM,gBAAgB,eAAe,CAAC,cAAc,WAAW,IAAI,cAAc;CACjF,MAAM,gBAAgB,gBAAgB,OAAO,sBAAsB;CACnE,MAAM,0BAA0B,wBAAwB,eAAe;EACrE,SAAS,OAAO,MAAM,IAAI,EAAY;EACtC,aAAa,KAAK;CACpB,GAAG,aAAa;CAEhB,MAAM,EAAE,OAAO,uBAAuB,kBAAkB,yBACtD,OAAO,kBACP,cAAc,eACd,gBACA,KAAK,sBAAuB,QAAwC,QACpE,aACF;CAmBA,OAAO;EAAE,QAjBM,eAA6B;GAC1C,GAAG,cAAc,MAAM;GACvB,OAAO;GACP,kBAAkB,wBAAwB,EAAE,OAAO,sBAAsB,IAAI;GAC7E,gBAAgB;IAAE,OAAO;IAAgB,OAAO;GAAQ;GACxD,cAAc;IAAE,OAAO;IAAc,OAAO;GAAiB;GAC7D,mBAAmB;IAAE,OAAO;IAAmB,OAAO;GAAe;GACrE,oBAAoB,gBAAgB,QAAQ,cAAc,WAAW,IACjE,cACA;IAAE,OAAO;IAAyB,OAAO;GAAmB;GAChE,GAAI,KAAK,cAAc,EAAE,aAAa;IAAE,OAAO;IAAkB,OAAO;GAAc,EAAE,IAAI,CAAC;GAC7F,GAAI,QAAQ,EAAE,YAAY;IAAE,OAAO;IAAY,OAAO,KAAK,cAAc,gBAAgB;GAAc,EAAE,IAAI,CAAC;EAChH,IAAI;GACF;GAAQ;GAAa;GAAuB;GAAgB;GAAc;GAAmB;GAAyB;GAAa;GACnI;GAAkB,KAAK;GAAa;GAAO;EAC7C,CAES;EAAQ;EAAe;EAAe;EAAsB;EAAW;CAAW;AAC7F"}
1
+ {"version":3,"file":"useSceneCanvasLayers.js","names":[],"sources":["../../../src/canvas/SceneCanvas/useSceneCanvasLayers.ts"],"sourcesContent":["import { useMemo, useRef, useState, type MutableRefObject } from 'react';\nimport type { ColorOverrideRegistry } from '@weasel-js/animator';\nimport type { Dispatcher } from '@weasel-js/routing';\nimport type { Affordance } from 'affordances/types';\nimport type { Node, NodeId, Scene } from 'core/scene/types';\nimport type { Bounds } from 'core/viewport/fitViewToBounds';\nimport type { PlaneMap } from 'core/viewport/parallax';\nimport type { View } from 'core/viewport/view';\nimport type { PathEditState } from 'features/paths/pathEditState';\nimport { usePathEditOverlayLayer } from 'features/paths/usePathEdit';\nimport type { rotationBadgeOf } from 'features/selection/overlay';\nimport type { PoseDescriptor } from 'interactions/actions/resize/geometry';\nimport type { HierarchicalAdapter } from '../buildSceneTree';\nimport { builtLayersOf, isCustomEntry, type CanvasLayers } from '../layerSlots';\nimport { createSlopsDebugLayer } from '../slopsDebugLayer';\nimport { useTargetBasePx } from 'core/device/useTargetBasePx';\nimport { targetSizesPx } from 'core/device/targets';\nimport type { ResizeHandleLayout } from 'interactions/actions/resize/cornerHandles';\nimport { mergeLayersWithDefaults } from './mergeLayers';\nimport type { SceneCanvasLayers } from './props';\nimport { useDispatcherOverlayLayer } from './useDispatcherOverlayLayer';\nimport { usePreviewGhostLayer } from './usePreviewGhostLayer';\nimport { useDepartureGhostLayer } from './useDepartureGhostLayer';\nimport { useEffectSourcesLayer } from 'features/pathEffects/useEffectSourcesLayer';\nimport type { Departures } from '../../animation/departures';\nimport { usePoseTransition, type PoseTransitionSeat } from '../../animation/poseTransition';\nimport { useSceneSlotLayers } from './useSceneSlotLayers';\nimport { useSelectionOverlayLayer } from './useSelectionOverlayLayer';\nimport { drawnBoundsScene } from '../derivedPath';\nimport { createSnapOutcomeStore, type SnapOutcomeStore } from 'features/snap/outcomeStore';\nimport { createSnapReadoutLayer } from 'features/snap/readoutLayer';\nimport type { SnapReadoutStyle } from 'features/snap/types';\n\n/**\n * The layer map `<SceneCanvas>` hands `<Canvas>`: the caller's `layers` over\n * the kit defaults, with the scene and selection-overlay slots built, and the\n * canvas's own layers anchored around them. Removed nodes leave just above\n * the scene, the preview ghost above them, a selected path effect's hidden sources above that, the dispatcher's\n * overlay (marquee, lasso) above those, and the\n * anchor overlay above the selection chrome.\n */\nexport function useSceneCanvasLayers<TData, TLayer extends string, TPose>(args: {\n /** `<SceneCanvas layers>`. Omitted, the result is the full default set. */\n layers: SceneCanvasLayers<Node<TData, TLayer, TPose>, TPose> | undefined;\n /** The device profile's, which sizes the default handles. */\n targetScale: number;\n scene: Scene<TData, TLayer, TPose>;\n adapter: HierarchicalAdapter<Node<TData, TLayer, TPose>, TPose>;\n poseDescriptor: PoseDescriptor<TPose>;\n alphaFor: ((id: string) => number) | undefined;\n colorOverrides: ColorOverrideRegistry | undefined;\n boundsOf: (id: string) => Bounds | null;\n planeOfNode: (id: string, view: View) => PlaneMap | null;\n /** `<SceneCanvas poseTransition>`, whose ghosts of removed nodes this draws. */\n poseTransition: PoseTransitionSeat<TPose> | null | undefined;\n /** Ids an in-flight gesture is ghosting. */\n previewIds: () => Iterable<string> | null;\n dispatcher: Dispatcher;\n /** Whether to mount the snap readout layer. */\n snapReadout: boolean;\n snapReadoutStyle?: SnapReadoutStyle;\n pathEditState: PathEditState;\n /** `debug.slops`: paint the hit regions of the chrome affordances. */\n slops: boolean;\n /** `geometry.boundsIncludeStroke`: whether chrome sits on the stroke. */\n boundsIncludeStroke: boolean;\n /** `selectTool`'s `handleHitRadius` and `resize.edgeHandles`, resolved here into\n * the one {@link ResizeHandleLayout} the overlay paints and the hit-test reads. */\n selectTool?: { handleHitRadius?: number; resize?: { edgeHandles?: boolean } };\n}): {\n layers: CanvasLayers;\n /** Where the selection overlay paints its rotate badge, or null. */\n rotationBadge: ReturnType<typeof rotationBadgeOf>;\n /** Which resize handles exist and their hit radius, for every hit-test of this canvas. */\n resizeHandles: ResizeHandleLayout;\n /** The affordances the gesture mounter hit-tests, which it publishes here\n * so the slops halos are the hit regions rather than a copy of them. */\n chromeAffordancesRef: MutableRefObject<readonly Affordance[]>;\n /** The marks the readout layer draws; the canvas's snap dep writes them. */\n snapStore: SnapOutcomeStore;\n /** The removed nodes the seat is seeing off. */\n departures: Departures<TPose, Node<TData, TLayer, TPose>>;\n} {\n const { scene, adapter, poseDescriptor, alphaFor, dispatcher, pathEditState, slops, targetScale } = args;\n\n const baseSizes = useTargetBasePx();\n const merged = useMemo(\n () => mergeLayersWithDefaults(args.layers, targetScale, baseSizes),\n [args.layers, targetScale, baseSizes],\n );\n\n const { config: sceneSlot, layers: sceneLayers } = useSceneSlotLayers({\n slot: merged.scene,\n scene,\n adapter,\n alphaFor,\n colorOverrides: args.colorOverrides,\n boundsOf: args.boundsOf,\n previewIds: args.previewIds,\n });\n // Takes the scene-wired slot, so a ghosted derived node still resolves its path.\n const previewLayer = usePreviewGhostLayer<TData, TLayer, TPose>({ scene, sceneSlot, dispatcher });\n const departures = usePoseTransition(scene, args.poseTransition);\n const departureLayer = useDepartureGhostLayer({ scene, sceneSlot, departures });\n const effectSourcesLayer = useEffectSourcesLayer(scene);\n const dispatcherOverlay = useDispatcherOverlayLayer({ dispatcher });\n\n const hitRadiusPx = args.selectTool?.handleHitRadius ?? targetSizesPx(targetScale, baseSizes).handle;\n const edges = args.selectTool?.resize?.edgeHandles ?? true;\n const resizeHandles = useMemo<ResizeHandleLayout>(() => ({ edges, hitRadiusPx }), [edges, hitRadiusPx]);\n\n const chromeAffordancesRef = useRef<readonly Affordance[]>([]);\n const slopsLayer = useMemo(\n () => createSlopsDebugLayer({ getAffordances: () => chromeAffordancesRef.current }),\n [],\n );\n\n const [snapStore] = useState(() => createSnapOutcomeStore());\n // Keyed on the style's values, so an inline `readoutStyle` literal keeps the layer.\n const { color, gapColor, lineWidth } = args.snapReadoutStyle ?? {};\n const snapReadoutLayer = useMemo(() => createSnapReadoutLayer(snapStore, {\n ...(color !== undefined ? { color } : {}),\n ...(gapColor !== undefined ? { gapColor } : {}),\n ...(lineWidth !== undefined ? { lineWidth } : {}),\n }), [snapStore, color, gapColor, lineWidth]);\n const overlaySlot = merged.pathEditingOverlay;\n const overlayConfig = overlaySlot && !isCustomEntry(overlaySlot) ? overlaySlot : undefined;\n const overlayAnchor = overlaySlot === null ? 'dispatcherOverlay' : 'pathEditingOverlay';\n const pathEditingOverlayLayer = usePathEditOverlayLayer(pathEditState, {\n nodeOf: (id) => scene.get(id as NodeId),\n planeOfNode: args.planeOfNode,\n }, overlayConfig);\n\n const { layer: selectionOverlayLayer, rotationBadge } = useSelectionOverlayLayer<TPose>(\n merged.selectionOverlay,\n pathEditState.getEditingIds,\n poseDescriptor,\n args.boundsIncludeStroke ? drawnBoundsScene(scene) : undefined,\n resizeHandles,\n );\n\n const layers = useMemo<CanvasLayers>(() => ({\n ...builtLayersOf(merged),\n scene: sceneLayers,\n selectionOverlay: selectionOverlayLayer ? { layer: selectionOverlayLayer } : null,\n departureGhost: { layer: departureLayer, after: 'scene' },\n previewGhost: { layer: previewLayer, after: 'departureGhost' },\n effectSources: { layer: effectSourcesLayer, after: 'previewGhost' },\n dispatcherOverlay: { layer: dispatcherOverlay, after: 'effectSources' },\n pathEditingOverlay: overlaySlot === null || isCustomEntry(overlaySlot)\n ? overlaySlot\n : { layer: pathEditingOverlayLayer, after: 'selectionOverlay' },\n ...(args.snapReadout ? { snapReadout: { layer: snapReadoutLayer, after: overlayAnchor } } : {}),\n ...(slops ? { slopsDebug: { layer: slopsLayer, after: args.snapReadout ? 'snapReadout' : overlayAnchor } } : {}),\n }), [\n merged, sceneLayers, selectionOverlayLayer, departureLayer, previewLayer, effectSourcesLayer, dispatcherOverlay, pathEditingOverlayLayer, overlaySlot, overlayAnchor,\n snapReadoutLayer, args.snapReadout, slops, slopsLayer,\n ]);\n\n return { layers, rotationBadge, resizeHandles, chromeAffordancesRef, snapStore, departures };\n}\n"],"mappings":"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"}
@@ -3,17 +3,16 @@ import { useCanvasTools, useFeatureBindings } from "./useCanvasTools.js";
3
3
  //#region src/canvas/SceneCanvas/useSceneCanvasTools.ts
4
4
  /** The canvas's tools, and the contributions and standard actions its presets bring. */
5
5
  function useSceneCanvasTools(args) {
6
- const { props, select, scene, selection, enabled } = args;
6
+ const { props, select, enabled } = args;
7
7
  const { tools, internal, takeover } = useCanvasTools({
8
8
  select,
9
- scene,
10
- selection,
11
9
  enabled,
12
10
  tools: props.tools,
13
11
  defaultTools: props.defaultTools,
14
12
  toolOptions: props.toolOptions,
15
13
  inertia: props.viewport?.inertia,
16
14
  ambient: props.ambient,
15
+ actions: props.actions,
17
16
  pressFeedback: props.longPress?.feedback,
18
17
  initialActiveTool: props.initialActiveTool,
19
18
  modes: props.modes,
@@ -1 +1 @@
1
- {"version":3,"file":"useSceneCanvasTools.js","names":[],"sources":["../../../src/canvas/SceneCanvas/useSceneCanvasTools.ts"],"sourcesContent":["import type { Scene } from 'core/scene/types';\nimport type { SelectionApi } from 'core/selection/useSelection';\nimport type { Tool } from '../../tools/overlayBinding';\nimport type { EnabledPresets, FeatureBindingOptions, PresetSource } from './features';\nimport type { SceneCanvasProps } from './props';\nimport { useCanvasTools, useFeatureBindings } from './useCanvasTools';\n\ntype Props = SceneCanvasProps<unknown, string, unknown>;\n\n/** The `<SceneCanvas>` props its tools and preset bindings read. */\nexport type SceneCanvasToolProps = Pick<\n Props,\n | 'tools' | 'defaultTools' | 'toolOptions' | 'viewport' | 'ambient' | 'longPress'\n | 'initialActiveTool' | 'modes' | 'onToolsCreated' | 'selectTool'\n>;\n\n/** The canvas's tools, and the contributions and standard actions its presets bring. */\nexport function useSceneCanvasTools(args: {\n props: SceneCanvasToolProps;\n select: Tool;\n /** The select tool's move options, which the selection's `move` binding takes. */\n move: unknown;\n scene: Scene<unknown, string, unknown>;\n selection: SelectionApi;\n enabled: EnabledPresets;\n presetSource: PresetSource;\n}) {\n const { props, select, scene, selection, enabled } = args;\n const { tools, internal, takeover } = useCanvasTools({\n select, scene, selection,\n enabled,\n tools: props.tools,\n defaultTools: props.defaultTools,\n toolOptions: props.toolOptions,\n inertia: props.viewport?.inertia,\n ambient: props.ambient,\n pressFeedback: props.longPress?.feedback,\n initialActiveTool: props.initialActiveTool,\n modes: props.modes,\n onToolsCreated: props.onToolsCreated,\n });\n const { contributions, standardActions } = useFeatureBindings({\n enabled, pool: args.presetSource.pool,\n tools,\n move: args.move as FeatureBindingOptions['move'],\n rotate: (props.selectTool?.rotate || undefined) as FeatureBindingOptions['rotate'],\n });\n return { tools, internal, takeover, contributions, standardActions };\n}\n"],"mappings":";;;;AAiBA,SAAgB,oBAAoB,MASjC;CACD,MAAM,EAAE,OAAO,QAAQ,OAAO,WAAW,YAAY;CACrD,MAAM,EAAE,OAAO,UAAU,aAAa,eAAe;EACnD;EAAQ;EAAO;EACf;EACA,OAAO,MAAM;EACb,cAAc,MAAM;EACpB,aAAa,MAAM;EACnB,SAAS,MAAM,UAAU;EACzB,SAAS,MAAM;EACf,eAAe,MAAM,WAAW;EAChC,mBAAmB,MAAM;EACzB,OAAO,MAAM;EACb,gBAAgB,MAAM;CACxB,CAAC;CACD,MAAM,EAAE,eAAe,oBAAoB,mBAAmB;EAC5D;EAAS,MAAM,KAAK,aAAa;EACjC;EACA,MAAM,KAAK;EACX,QAAS,MAAM,YAAY,UAAU;CACvC,CAAC;CACD,OAAO;EAAE;EAAO;EAAU;EAAU;EAAe;CAAgB;AACrE"}
1
+ {"version":3,"file":"useSceneCanvasTools.js","names":[],"sources":["../../../src/canvas/SceneCanvas/useSceneCanvasTools.ts"],"sourcesContent":["import type { Tool } from '../../tools/overlayBinding';\nimport type { EnabledPresets, FeatureBindingOptions, PresetSource } from './features';\nimport type { SceneCanvasProps } from './props';\nimport { useCanvasTools, useFeatureBindings } from './useCanvasTools';\n\ntype Props = SceneCanvasProps<unknown, string, unknown>;\n\n/** The `<SceneCanvas>` props its tools and preset bindings read. */\nexport type SceneCanvasToolProps = Pick<\n Props,\n | 'tools' | 'defaultTools' | 'toolOptions' | 'viewport' | 'ambient' | 'longPress'\n | 'initialActiveTool' | 'modes' | 'onToolsCreated' | 'selectTool' | 'actions'\n>;\n\n/** The canvas's tools, and the contributions and standard actions its presets bring. */\nexport function useSceneCanvasTools(args: {\n props: SceneCanvasToolProps;\n select: Tool;\n /** The select tool's move options, which the selection's `move` binding takes. */\n move: unknown;\n enabled: EnabledPresets;\n presetSource: PresetSource;\n}) {\n const { props, select, enabled } = args;\n const { tools, internal, takeover } = useCanvasTools({\n select,\n enabled,\n tools: props.tools,\n defaultTools: props.defaultTools,\n toolOptions: props.toolOptions,\n inertia: props.viewport?.inertia,\n ambient: props.ambient,\n actions: props.actions,\n pressFeedback: props.longPress?.feedback,\n initialActiveTool: props.initialActiveTool,\n modes: props.modes,\n onToolsCreated: props.onToolsCreated,\n });\n const { contributions, standardActions } = useFeatureBindings({\n enabled, pool: args.presetSource.pool,\n tools,\n move: args.move as FeatureBindingOptions['move'],\n rotate: (props.selectTool?.rotate || undefined) as FeatureBindingOptions['rotate'],\n });\n return { tools, internal, takeover, contributions, standardActions };\n}\n"],"mappings":";;;;AAeA,SAAgB,oBAAoB,MAOjC;CACD,MAAM,EAAE,OAAO,QAAQ,YAAY;CACnC,MAAM,EAAE,OAAO,UAAU,aAAa,eAAe;EACnD;EACA;EACA,OAAO,MAAM;EACb,cAAc,MAAM;EACpB,aAAa,MAAM;EACnB,SAAS,MAAM,UAAU;EACzB,SAAS,MAAM;EACf,SAAS,MAAM;EACf,eAAe,MAAM,WAAW;EAChC,mBAAmB,MAAM;EACzB,OAAO,MAAM;EACb,gBAAgB,MAAM;CACxB,CAAC;CACD,MAAM,EAAE,eAAe,oBAAoB,mBAAmB;EAC5D;EAAS,MAAM,KAAK,aAAa;EACjC;EACA,MAAM,KAAK;EACX,QAAS,MAAM,YAAY,UAAU;CACvC,CAAC;CACD,OAAO;EAAE;EAAO;EAAU;EAAU;EAAe;CAAgB;AACrE"}
@@ -16,7 +16,7 @@ import { useLatest } from "@weasel-js/react";
16
16
  * pointer to capture, so whichever view is under the cursor owns the point.
17
17
  */
18
18
  function useSceneHover(args) {
19
- const { canvasApiRef, viewRef, nodeAtPointRef, enabled } = args;
19
+ const { canvasApiRef, viewRef, nodeAtPointRef, enabled, onChange } = args;
20
20
  const surfaceViewRegistry = useOptionalViewRegistry();
21
21
  return useHoverTracking({
22
22
  nodeAtClientPoint: (clientX, clientY) => {
@@ -32,7 +32,8 @@ function useSceneHover(args) {
32
32
  } : view);
33
33
  return hit ? { id: hit.id } : null;
34
34
  },
35
- enabled
35
+ enabled,
36
+ ...onChange ? { onChange } : {}
36
37
  });
37
38
  }
38
39
  /**
@@ -42,17 +43,16 @@ function useSceneHover(args) {
42
43
  * An unselectable canvas hides the marquee and lasso by default: every
43
44
  * selection write no-ops there, so the select tool's empty-drag binding still
44
45
  * claims the gesture, keeping it from falling through to an ambient drag such
45
- * as insert, but paints nothing. `rotateOff` hides the rotation handle.
46
+ * as insert, but paints nothing.
46
47
  */
47
48
  function useChromeRules(args) {
48
- const { enabled, selectable, rotateOff, chromeVisibility } = args;
49
+ const { enabled, selectable, chromeVisibility } = args;
49
50
  return useMemo(() => {
50
51
  const defaults = presetChromeRules(enabled, PRESET_OWNED_CHROME);
51
52
  if (!selectable) {
52
53
  defaults["action.marquee"] = never;
53
54
  defaults["action.lasso"] = never;
54
55
  }
55
- if (rotateOff) defaults["selection.rotation-handle"] = never;
56
56
  return {
57
57
  ...defaults,
58
58
  ...chromeVisibility
@@ -60,7 +60,6 @@ function useChromeRules(args) {
60
60
  }, [
61
61
  chromeVisibility,
62
62
  selectable,
63
- rotateOff,
64
63
  enabled
65
64
  ]);
66
65
  }
@@ -93,7 +92,7 @@ function useSceneCanvasChrome(args) {
93
92
  const { getHover, canvasRef: trackHoverOn } = useSceneHover({
94
93
  ...args.hover,
95
94
  viewRef,
96
- enabled: rules.chromeVisibility !== void 0
95
+ enabled: rules.chromeVisibility !== void 0 || args.hover.onChange !== void 0
97
96
  });
98
97
  return {
99
98
  ...useSurfaceChromeCaps({
@@ -1 +1 @@
1
- {"version":3,"file":"useSceneChrome.js","names":[],"sources":["../../../src/canvas/SceneCanvas/useSceneChrome.ts"],"sourcesContent":["import { useCallback, useMemo, type RefObject } from 'react';\nimport { useLatest } from '@weasel-js/react';\nimport type { Dispatcher, RuleCtx } from '@weasel-js/routing';\nimport type { NodeId } from 'core/scene/types';\nimport type { View } from 'core/viewport/view';\nimport { never, useHoverTracking, type HoverTracking, type VisibilityRules } from 'features/chrome-caps';\nimport {\n useChromeCaps,\n type ChromeCaps,\n type ChromeCapsSource,\n type ViewRuleInputs,\n} from 'features/chrome-caps/useChromeCaps';\nimport type { CanvasExtensionApi } from '../canvasExtension';\nimport { useOptionalViewRegistry } from '../viewRegistry';\nimport { presetChromeRules, type EnabledPresets } from './features';\nimport { PRESET_OWNED_CHROME } from './presets/chrome';\nimport type { NodeAtPoint } from './useNodeAtPoint';\nimport { worldPointAt } from './worldPointAt';\n\n/**\n * The node under the pointer, for `RuleCtx.hover`. One lookup, not a\n * client-to-world thunk beside a picker: the point and the camera its\n * tolerance converts against have to come from the same view. Hover has no\n * pointer to capture, so whichever view is under the cursor owns the point.\n */\nexport function useSceneHover(args: {\n canvasApiRef: RefObject<Pick<CanvasExtensionApi, 'clientToWorld'> | null>;\n /** The surface's own camera, for a point no declared view claims. */\n viewRef: { readonly current: View };\n nodeAtPointRef: { readonly current: NodeAtPoint | undefined };\n enabled: boolean;\n}): HoverTracking {\n const { canvasApiRef, viewRef, nodeAtPointRef, enabled } = args;\n const surfaceViewRegistry = useOptionalViewRegistry();\n return useHoverTracking({\n nodeAtClientPoint: (clientX, clientY) => {\n const api = canvasApiRef.current;\n if (!api) return null;\n const target = surfaceViewRegistry?.resolver.at(null, clientX, clientY);\n const view = target?.view ?? viewRef.current;\n const [x, y] = worldPointAt(api, target, clientX, clientY);\n // A view judges its own layers; the surface's gate is the picker's default.\n const reg = target?.id != null\n ? surfaceViewRegistry?.list().find((r) => r.id === target.id)\n : undefined;\n const hit = nodeAtPointRef.current?.(\n x, y, reg ? { scale: view.scale, layerIsPainted: reg.layerIsPainted } : view,\n );\n return hit ? { id: hit.id as NodeId } : null;\n },\n enabled,\n });\n}\n\n/**\n * The surface's chrome-visibility rules: the presets' defaults under the\n * consumer's `chromeVisibility`, which wins.\n *\n * An unselectable canvas hides the marquee and lasso by default: every\n * selection write no-ops there, so the select tool's empty-drag binding still\n * claims the gesture, keeping it from falling through to an ambient drag such\n * as insert, but paints nothing. `rotateOff` hides the rotation handle.\n */\nexport function useChromeRules(args: {\n enabled: EnabledPresets;\n selectable: boolean;\n /** `selectTool.rotate === false`. */\n rotateOff: boolean;\n chromeVisibility: VisibilityRules | undefined;\n}): VisibilityRules {\n const { enabled, selectable, rotateOff, chromeVisibility } = args;\n return useMemo(() => {\n const defaults = presetChromeRules(enabled, PRESET_OWNED_CHROME);\n if (!selectable) {\n defaults['action.marquee'] = never;\n defaults['action.lasso'] = never;\n }\n if (rotateOff) defaults['selection.rotation-handle'] = never;\n return { ...defaults, ...chromeVisibility };\n }, [chromeVisibility, selectable, rotateOff, enabled]);\n}\n\n/** The chrome-caps answers for the surface's own view. */\nexport function useSurfaceChromeCaps(args: {\n source: ChromeCapsSource;\n /** The selection as rendered. `SelectionApi.current` can be a live getter\n * that runs ahead of the commit the painted chrome was built from. */\n selection: readonly NodeId[];\n viewRef: { readonly current: View };\n dispatcher: Pick<Dispatcher, 'getActiveAction'>;\n}): {\n chromeCaps: ChromeCaps;\n getIsVisible: () => (id: string) => boolean;\n getRuleCtx: () => RuleCtx | undefined;\n} {\n const { viewRef, dispatcher } = args;\n const chromeCaps = useChromeCaps(args.source);\n const committedSelectionRef = useLatest(args.selection);\n const currentRuleInputs = useCallback((): ViewRuleInputs => ({\n selection: committedSelectionRef.current,\n view: viewRef.current,\n action: dispatcher.getActiveAction(),\n }), [dispatcher, committedSelectionRef, viewRef]);\n const getIsVisible = useCallback(\n (): ((id: string) => boolean) => chromeCaps.isVisible(currentRuleInputs()),\n [chromeCaps, currentRuleInputs],\n );\n const getRuleCtx = useCallback(\n () => chromeCaps.ruleCtx(currentRuleInputs()),\n [chromeCaps, currentRuleInputs],\n );\n return { chromeCaps, getIsVisible, getRuleCtx };\n}\n\n/**\n * The surface's chrome: hover tracking, the visibility rules, and the chrome-caps answers they\n * feed. `source` is the chrome-caps source minus the parts built here.\n */\nexport function useSceneCanvasChrome(args: {\n source: Omit<ChromeCapsSource, 'rules' | 'getHover'>;\n rules: Parameters<typeof useChromeRules>[0];\n hover: Omit<Parameters<typeof useSceneHover>[0], 'enabled' | 'viewRef'>;\n selection: readonly NodeId[];\n viewRef: { readonly current: View };\n dispatcher: Pick<Dispatcher, 'getActiveAction'>;\n}) {\n const { rules, viewRef } = args;\n const { getHover, canvasRef: trackHoverOn } = useSceneHover({\n ...args.hover, viewRef, enabled: rules.chromeVisibility !== undefined,\n });\n const chromeRules = useChromeRules(rules);\n const caps = useSurfaceChromeCaps({\n source: { rules: chromeRules, getHover, ...args.source },\n selection: args.selection,\n viewRef,\n dispatcher: args.dispatcher,\n });\n return { ...caps, trackHoverOn };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAyBA,SAAgB,cAAc,MAMZ;CAChB,MAAM,EAAE,cAAc,SAAS,gBAAgB,YAAY;CAC3D,MAAM,sBAAsB,wBAAwB;CACpD,OAAO,iBAAiB;EACtB,oBAAoB,SAAS,YAAY;GACvC,MAAM,MAAM,aAAa;GACzB,IAAI,CAAC,KAAK,OAAO;GACjB,MAAM,SAAS,qBAAqB,SAAS,GAAG,MAAM,SAAS,OAAO;GACtE,MAAM,OAAO,QAAQ,QAAQ,QAAQ;GACrC,MAAM,CAAC,GAAG,KAAK,aAAa,KAAK,QAAQ,SAAS,OAAO;GAEzD,MAAM,MAAM,QAAQ,MAAM,OACtB,qBAAqB,KAAK,CAAC,CAAC,MAAM,MAAM,EAAE,OAAO,OAAO,EAAE,IAC1D;GACJ,MAAM,MAAM,eAAe,UACzB,GAAG,GAAG,MAAM;IAAE,OAAO,KAAK;IAAO,gBAAgB,IAAI;GAAe,IAAI,IAC1E;GACA,OAAO,MAAM,EAAE,IAAI,IAAI,GAAa,IAAI;EAC1C;EACA;CACF,CAAC;AACH;;;;;;;;;;AAWA,SAAgB,eAAe,MAMX;CAClB,MAAM,EAAE,SAAS,YAAY,WAAW,qBAAqB;CAC7D,OAAO,cAAc;EACnB,MAAM,WAAW,kBAAkB,SAAS,mBAAmB;EAC/D,IAAI,CAAC,YAAY;GACf,SAAS,oBAAoB;GAC7B,SAAS,kBAAkB;EAC7B;EACA,IAAI,WAAW,SAAS,+BAA+B;EACvD,OAAO;GAAE,GAAG;GAAU,GAAG;EAAiB;CAC5C,GAAG;EAAC;EAAkB;EAAY;EAAW;CAAO,CAAC;AACvD;;AAGA,SAAgB,qBAAqB,MAWnC;CACA,MAAM,EAAE,SAAS,eAAe;CAChC,MAAM,aAAa,cAAc,KAAK,MAAM;CAC5C,MAAM,wBAAwB,UAAU,KAAK,SAAS;CACtD,MAAM,oBAAoB,mBAAmC;EAC3D,WAAW,sBAAsB;EACjC,MAAM,QAAQ;EACd,QAAQ,WAAW,gBAAgB;CACrC,IAAI;EAAC;EAAY;EAAuB;CAAO,CAAC;CAShD,OAAO;EAAE;EAAY,cARA,kBACc,WAAW,UAAU,kBAAkB,CAAC,GACzE,CAAC,YAAY,iBAAiB,CAMX;EAAc,YAJhB,kBACX,WAAW,QAAQ,kBAAkB,CAAC,GAC5C,CAAC,YAAY,iBAAiB,CAEG;CAAW;AAChD;;;;;AAMA,SAAgB,qBAAqB,MAOlC;CACD,MAAM,EAAE,OAAO,YAAY;CAC3B,MAAM,EAAE,UAAU,WAAW,iBAAiB,cAAc;EAC1D,GAAG,KAAK;EAAO;EAAS,SAAS,MAAM,qBAAqB;CAC9D,CAAC;CAQD,OAAO;EAAE,GANI,qBAAqB;GAChC,QAAQ;IAAE,OAFQ,eAAe,KAEhB;IAAa;IAAU,GAAG,KAAK;GAAO;GACvD,WAAW,KAAK;GAChB;GACA,YAAY,KAAK;EACnB,CACY;EAAM;CAAa;AACjC"}
1
+ {"version":3,"file":"useSceneChrome.js","names":[],"sources":["../../../src/canvas/SceneCanvas/useSceneChrome.ts"],"sourcesContent":["import { useCallback, useMemo, type RefObject } from 'react';\nimport { useLatest } from '@weasel-js/react';\nimport type { Dispatcher, RuleCtx } from '@weasel-js/routing';\nimport type { NodeId } from 'core/scene/types';\nimport type { View } from 'core/viewport/view';\nimport { never, useHoverTracking, type HoverTracking, type VisibilityRules } from 'features/chrome-caps';\nimport {\n useChromeCaps,\n type ChromeCaps,\n type ChromeCapsSource,\n type ViewRuleInputs,\n} from 'features/chrome-caps/useChromeCaps';\nimport type { CanvasExtensionApi } from '../canvasExtension';\nimport { useOptionalViewRegistry } from '../viewRegistry';\nimport { presetChromeRules, type EnabledPresets } from './features';\nimport { PRESET_OWNED_CHROME } from './presets/chrome';\nimport type { NodeAtPoint } from './useNodeAtPoint';\nimport { worldPointAt } from './worldPointAt';\n\n/**\n * The node under the pointer, for `RuleCtx.hover`. One lookup, not a\n * client-to-world thunk beside a picker: the point and the camera its\n * tolerance converts against have to come from the same view. Hover has no\n * pointer to capture, so whichever view is under the cursor owns the point.\n */\nexport function useSceneHover(args: {\n canvasApiRef: RefObject<Pick<CanvasExtensionApi, 'clientToWorld'> | null>;\n /** The surface's own camera, for a point no declared view claims. */\n viewRef: { readonly current: View };\n nodeAtPointRef: { readonly current: NodeAtPoint | undefined };\n enabled: boolean;\n onChange?: (id: NodeId | null) => void;\n}): HoverTracking {\n const { canvasApiRef, viewRef, nodeAtPointRef, enabled, onChange } = args;\n const surfaceViewRegistry = useOptionalViewRegistry();\n return useHoverTracking({\n nodeAtClientPoint: (clientX, clientY) => {\n const api = canvasApiRef.current;\n if (!api) return null;\n const target = surfaceViewRegistry?.resolver.at(null, clientX, clientY);\n const view = target?.view ?? viewRef.current;\n const [x, y] = worldPointAt(api, target, clientX, clientY);\n // A view judges its own layers; the surface's gate is the picker's default.\n const reg = target?.id != null\n ? surfaceViewRegistry?.list().find((r) => r.id === target.id)\n : undefined;\n const hit = nodeAtPointRef.current?.(\n x, y, reg ? { scale: view.scale, layerIsPainted: reg.layerIsPainted } : view,\n );\n return hit ? { id: hit.id as NodeId } : null;\n },\n enabled,\n ...(onChange ? { onChange } : {}),\n });\n}\n\n/**\n * The surface's chrome-visibility rules: the presets' defaults under the\n * consumer's `chromeVisibility`, which wins.\n *\n * An unselectable canvas hides the marquee and lasso by default: every\n * selection write no-ops there, so the select tool's empty-drag binding still\n * claims the gesture, keeping it from falling through to an ambient drag such\n * as insert, but paints nothing.\n */\nexport function useChromeRules(args: {\n enabled: EnabledPresets;\n selectable: boolean;\n chromeVisibility: VisibilityRules | undefined;\n}): VisibilityRules {\n const { enabled, selectable, chromeVisibility } = args;\n return useMemo(() => {\n const defaults = presetChromeRules(enabled, PRESET_OWNED_CHROME);\n if (!selectable) {\n defaults['action.marquee'] = never;\n defaults['action.lasso'] = never;\n }\n return { ...defaults, ...chromeVisibility };\n }, [chromeVisibility, selectable, enabled]);\n}\n\n/** The chrome-caps answers for the surface's own view. */\nexport function useSurfaceChromeCaps(args: {\n source: ChromeCapsSource;\n /** The selection as rendered. `SelectionApi.current` can be a live getter\n * that runs ahead of the commit the painted chrome was built from. */\n selection: readonly NodeId[];\n viewRef: { readonly current: View };\n dispatcher: Pick<Dispatcher, 'getActiveAction'>;\n}): {\n chromeCaps: ChromeCaps;\n getIsVisible: () => (id: string) => boolean;\n getRuleCtx: () => RuleCtx | undefined;\n} {\n const { viewRef, dispatcher } = args;\n const chromeCaps = useChromeCaps(args.source);\n const committedSelectionRef = useLatest(args.selection);\n const currentRuleInputs = useCallback((): ViewRuleInputs => ({\n selection: committedSelectionRef.current,\n view: viewRef.current,\n action: dispatcher.getActiveAction(),\n }), [dispatcher, committedSelectionRef, viewRef]);\n const getIsVisible = useCallback(\n (): ((id: string) => boolean) => chromeCaps.isVisible(currentRuleInputs()),\n [chromeCaps, currentRuleInputs],\n );\n const getRuleCtx = useCallback(\n () => chromeCaps.ruleCtx(currentRuleInputs()),\n [chromeCaps, currentRuleInputs],\n );\n return { chromeCaps, getIsVisible, getRuleCtx };\n}\n\n/**\n * The surface's chrome: hover tracking, the visibility rules, and the chrome-caps answers they\n * feed. `source` is the chrome-caps source minus the parts built here.\n */\nexport function useSceneCanvasChrome(args: {\n source: Omit<ChromeCapsSource, 'rules' | 'getHover'>;\n rules: Parameters<typeof useChromeRules>[0];\n hover: Omit<Parameters<typeof useSceneHover>[0], 'enabled' | 'viewRef'>;\n selection: readonly NodeId[];\n viewRef: { readonly current: View };\n dispatcher: Pick<Dispatcher, 'getActiveAction'>;\n}) {\n const { rules, viewRef } = args;\n const { getHover, canvasRef: trackHoverOn } = useSceneHover({\n ...args.hover, viewRef, enabled: rules.chromeVisibility !== undefined || args.hover.onChange !== undefined,\n });\n const chromeRules = useChromeRules(rules);\n const caps = useSurfaceChromeCaps({\n source: { rules: chromeRules, getHover, ...args.source },\n selection: args.selection,\n viewRef,\n dispatcher: args.dispatcher,\n });\n return { ...caps, trackHoverOn };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAyBA,SAAgB,cAAc,MAOZ;CAChB,MAAM,EAAE,cAAc,SAAS,gBAAgB,SAAS,aAAa;CACrE,MAAM,sBAAsB,wBAAwB;CACpD,OAAO,iBAAiB;EACtB,oBAAoB,SAAS,YAAY;GACvC,MAAM,MAAM,aAAa;GACzB,IAAI,CAAC,KAAK,OAAO;GACjB,MAAM,SAAS,qBAAqB,SAAS,GAAG,MAAM,SAAS,OAAO;GACtE,MAAM,OAAO,QAAQ,QAAQ,QAAQ;GACrC,MAAM,CAAC,GAAG,KAAK,aAAa,KAAK,QAAQ,SAAS,OAAO;GAEzD,MAAM,MAAM,QAAQ,MAAM,OACtB,qBAAqB,KAAK,CAAC,CAAC,MAAM,MAAM,EAAE,OAAO,OAAO,EAAE,IAC1D;GACJ,MAAM,MAAM,eAAe,UACzB,GAAG,GAAG,MAAM;IAAE,OAAO,KAAK;IAAO,gBAAgB,IAAI;GAAe,IAAI,IAC1E;GACA,OAAO,MAAM,EAAE,IAAI,IAAI,GAAa,IAAI;EAC1C;EACA;EACA,GAAI,WAAW,EAAE,SAAS,IAAI,CAAC;CACjC,CAAC;AACH;;;;;;;;;;AAWA,SAAgB,eAAe,MAIX;CAClB,MAAM,EAAE,SAAS,YAAY,qBAAqB;CAClD,OAAO,cAAc;EACnB,MAAM,WAAW,kBAAkB,SAAS,mBAAmB;EAC/D,IAAI,CAAC,YAAY;GACf,SAAS,oBAAoB;GAC7B,SAAS,kBAAkB;EAC7B;EACA,OAAO;GAAE,GAAG;GAAU,GAAG;EAAiB;CAC5C,GAAG;EAAC;EAAkB;EAAY;CAAO,CAAC;AAC5C;;AAGA,SAAgB,qBAAqB,MAWnC;CACA,MAAM,EAAE,SAAS,eAAe;CAChC,MAAM,aAAa,cAAc,KAAK,MAAM;CAC5C,MAAM,wBAAwB,UAAU,KAAK,SAAS;CACtD,MAAM,oBAAoB,mBAAmC;EAC3D,WAAW,sBAAsB;EACjC,MAAM,QAAQ;EACd,QAAQ,WAAW,gBAAgB;CACrC,IAAI;EAAC;EAAY;EAAuB;CAAO,CAAC;CAShD,OAAO;EAAE;EAAY,cARA,kBACc,WAAW,UAAU,kBAAkB,CAAC,GACzE,CAAC,YAAY,iBAAiB,CAMX;EAAc,YAJhB,kBACX,WAAW,QAAQ,kBAAkB,CAAC,GAC5C,CAAC,YAAY,iBAAiB,CAEG;CAAW;AAChD;;;;;AAMA,SAAgB,qBAAqB,MAOlC;CACD,MAAM,EAAE,OAAO,YAAY;CAC3B,MAAM,EAAE,UAAU,WAAW,iBAAiB,cAAc;EAC1D,GAAG,KAAK;EAAO;EAAS,SAAS,MAAM,qBAAqB,UAAa,KAAK,MAAM,aAAa;CACnG,CAAC;CAQD,OAAO;EAAE,GANI,qBAAqB;GAChC,QAAQ;IAAE,OAFQ,eAAe,KAEhB;IAAa;IAAU,GAAG,KAAK;GAAO;GACvD,WAAW,KAAK;GAChB;GACA,YAAY,KAAK;EACnB,CACY;EAAM;CAAa;AACjC"}
@@ -1,13 +1,14 @@
1
1
  import { EMPTY_CHROME_STATE } from "../../core/selection/chromeState.js";
2
- import { useDispatchDepSources } from "../deps/dispatchSources.js";
3
2
  import { anchorStateFrom, buildAffordanceAt, buildClassifyTarget, layerAffordance } from "../affordanceAt.js";
4
- import { pathFromPlane } from "../planeClips.js";
5
3
  import { useOptionalViewRegistry } from "../viewRegistry.js";
4
+ import { useDispatchDepSources } from "../deps/dispatchSources.js";
5
+ import { pathFromPlane } from "../planeClips.js";
6
+ import { VIEW_MARKER_ENTRY_ID } from "../../features/viewports/viewMarkerDrag.js";
6
7
  import { useKitSettingsDepSource } from "../deps/kitSettings.js";
7
8
  import { useChromeAffordances } from "./useChromeAffordances.js";
8
9
  import { useSurfaceRouting } from "./useSurfaceRouting.js";
9
10
  import { traceConversion } from "./coordTrace.js";
10
- import { useCallback, useInsertionEffect, useMemo, useState } from "react";
11
+ import { useCallback, useEffect, useInsertionEffect, useMemo, useState } from "react";
11
12
  import { useLatest } from "@weasel-js/react";
12
13
  import { createLongPressStore } from "@weasel-js/routing";
13
14
  import { useActionsRegistry, useDepRegistry, useGestureDispatcher } from "@weasel-js/routing/react";
@@ -57,9 +58,22 @@ function useAffordanceAt(inputs, depRegistry, viewRegistry) {
57
58
  return (worldPoint) => {
58
59
  const extra = canvasApiRef.current?.hitTestExtras?.(worldPoint.x, worldPoint.y);
59
60
  if (extra) return layerAffordance(extra.layerId, extra.hit);
61
+ const marker = viewRegistry?.markerAt(null, worldPoint);
62
+ if (marker) return marker;
60
63
  return affordanceAt ? affordanceAt(worldPoint) : null;
61
64
  };
62
- }, [affordanceAt, canvasApiRef]);
65
+ }, [
66
+ affordanceAt,
67
+ canvasApiRef,
68
+ viewRegistry
69
+ ]);
70
+ }
71
+ /** Markers take presses only while the routed tools carry the marker drag:
72
+ * `actions={null}` and a tools takeover both leave it out. */
73
+ function useMarkerGate(viewRegistry, ambient) {
74
+ const installed = ambient.some((entry) => entry.id === VIEW_MARKER_ENTRY_ID);
75
+ const installedRef = useLatest(installed);
76
+ useEffect(() => viewRegistry?.gateMarkers(() => installedRef.current), [viewRegistry, installedRef]);
63
77
  }
64
78
  /** Which body a world point lands on, its selection state, and its routing kind. */
65
79
  function useClassifyTarget(inputs, kindOfNodeRef) {
@@ -86,7 +100,7 @@ function useClassifyTarget(inputs, kindOfNodeRef) {
86
100
  }
87
101
  /** Runs this canvas's gesture dispatcher over its tools, contributions, and chrome. */
88
102
  function useSceneGestureDispatcher(inputs) {
89
- const { canvasRef, canvasApiRef, tools, contributions, enabled, keyboard, claimKeys, viewRef, kindOfNode, dispatcher, getRuleCtx, onDoubleClick, onClick, longPress: { duration: longPressDuration, haptics: longPressHaptics } = {} } = inputs;
103
+ const { canvasRef, canvasApiRef, tools, contributions, enabled, keyboard, claimKeys, viewRef, kindOfNode, dispatcher, traces, getRuleCtx, onDoubleClick, onClick, longPress: { duration: longPressDuration, haptics: longPressHaptics } = {} } = inputs;
90
104
  const registry = useActionsRegistry();
91
105
  const depRegistry = useDepRegistry();
92
106
  const viewRegistry = useOptionalViewRegistry();
@@ -102,6 +116,7 @@ function useSceneGestureDispatcher(inputs) {
102
116
  contributions
103
117
  ]);
104
118
  const kindOfNodeRef = useLatest(kindOfNode);
119
+ useMarkerGate(viewRegistry, tools.ambient);
105
120
  const affordanceWithLayers = useAffordanceAt(inputs, depRegistry, viewRegistry);
106
121
  const classifyTarget = useClassifyTarget(inputs, kindOfNodeRef);
107
122
  const clientToWorld = useCallback((clientX, clientY) => {
@@ -111,12 +126,13 @@ function useSceneGestureDispatcher(inputs) {
111
126
  x,
112
127
  y
113
128
  };
114
- traceConversion(clientX, clientY, api ? canvasRef.current : null, viewRef?.current, world);
129
+ traceConversion(traces.coords, clientX, clientY, api ? canvasRef.current : null, viewRef?.current, world);
115
130
  return world;
116
131
  }, [
117
132
  canvasRef,
118
133
  canvasApiRef,
119
- viewRef
134
+ viewRef,
135
+ traces.coords
120
136
  ]);
121
137
  const requestRedraw = useCallback(() => {
122
138
  canvasApiRef.current?.requestRedraw?.();
@@ -144,6 +160,7 @@ function useSceneGestureDispatcher(inputs) {
144
160
  affordanceAt: affordanceWithLayers,
145
161
  classifyTarget,
146
162
  dispatcher,
163
+ trace: traces.dispatch,
147
164
  clientToWorld,
148
165
  requestRedraw,
149
166
  paintedCursor,