@weasel-js/core 1.13.0-rc.0 → 1.14.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 (745) hide show
  1. package/CHANGELOG.md +408 -0
  2. package/README.md +8 -12
  3. package/dist/affordances/hitAffordanceRegions.js +1 -1
  4. package/dist/affordances/hitAffordanceRegions.js.map +1 -1
  5. package/dist/affordances/pathAnchors.js.map +1 -1
  6. package/dist/animation/clipTargets.js +1 -1
  7. package/dist/animation/clipTargets.js.map +1 -1
  8. package/dist/animation/poseTarget.js +5 -32
  9. package/dist/animation/poseTarget.js.map +1 -1
  10. package/dist/{autoPoseDescriptor-CZ1eXbzY.d.ts → autoPoseDescriptor-C25QVb0W.d.ts} +1 -1
  11. package/dist/barrel/canvas.js +8 -8
  12. package/dist/barrel/chrome.js +9 -9
  13. package/dist/barrel/input.js +1 -1
  14. package/dist/barrel/interactions.js +3 -3
  15. package/dist/barrel/paint.js +2 -2
  16. package/dist/barrel/paths.js +19 -17
  17. package/dist/barrel/renderer.js +11 -7
  18. package/dist/barrel/routing.js +4 -1
  19. package/dist/barrel/scene.js +16 -12
  20. package/dist/barrel/text.js +5 -5
  21. package/dist/barrel/viewport.js +8 -8
  22. package/dist/canvas/Canvas.js +2 -2
  23. package/dist/canvas/Canvas.js.map +1 -1
  24. package/dist/canvas/CanvasView.js +20 -14
  25. package/dist/canvas/CanvasView.js.map +1 -1
  26. package/dist/canvas/GestureReason.js +64 -0
  27. package/dist/canvas/GestureReason.js.map +1 -0
  28. package/dist/canvas/GestureReason.module.js +7 -0
  29. package/dist/canvas/GestureReason.module.js.map +1 -0
  30. package/dist/canvas/LeanSceneCanvas.js +3 -1
  31. package/dist/canvas/LeanSceneCanvas.js.map +1 -1
  32. package/dist/canvas/NodeShape.js +2 -0
  33. package/dist/canvas/NodeShape.js.map +1 -1
  34. package/dist/canvas/PickHud.js +7 -3
  35. package/dist/canvas/PickHud.js.map +1 -1
  36. package/dist/canvas/SceneCanvas/CanvasKitProviders.js +1 -1
  37. package/dist/canvas/SceneCanvas/CanvasKitProviders.js.map +1 -1
  38. package/dist/canvas/SceneCanvas/DevHuds.js +2 -2
  39. package/dist/canvas/SceneCanvas/DevHuds.js.map +1 -1
  40. package/dist/canvas/SceneCanvas/PointerProviderIfRoot.js +4 -2
  41. package/dist/canvas/SceneCanvas/PointerProviderIfRoot.js.map +1 -1
  42. package/dist/canvas/SceneCanvas/SceneCanvasInput.js +3 -1
  43. package/dist/canvas/SceneCanvas/SceneCanvasInput.js.map +1 -1
  44. package/dist/canvas/SceneCanvas/brushOverlay.js.map +1 -1
  45. package/dist/canvas/SceneCanvas/builtinToolSets.js +17 -9
  46. package/dist/canvas/SceneCanvas/builtinToolSets.js.map +1 -1
  47. package/dist/canvas/SceneCanvas/canvasPassThrough.js +2 -1
  48. package/dist/canvas/SceneCanvas/canvasPassThrough.js.map +1 -1
  49. package/dist/canvas/SceneCanvas/defaultNodeProperties.js +75 -19
  50. package/dist/canvas/SceneCanvas/defaultNodeProperties.js.map +1 -1
  51. package/dist/canvas/SceneCanvas/defaultNodeRouting.js +7 -1
  52. package/dist/canvas/SceneCanvas/defaultNodeRouting.js.map +1 -1
  53. package/dist/canvas/SceneCanvas/defaultTextEditor.js +108 -0
  54. package/dist/canvas/SceneCanvas/defaultTextEditor.js.map +1 -0
  55. package/dist/canvas/SceneCanvas/describePresets.js +47 -0
  56. package/dist/canvas/SceneCanvas/describePresets.js.map +1 -0
  57. package/dist/canvas/SceneCanvas/features.js +57 -16
  58. package/dist/canvas/SceneCanvas/features.js.map +1 -1
  59. package/dist/canvas/SceneCanvas/mergeLayers.js +10 -1
  60. package/dist/canvas/SceneCanvas/mergeLayers.js.map +1 -1
  61. package/dist/canvas/SceneCanvas/namedPresets.js +52 -24
  62. package/dist/canvas/SceneCanvas/namedPresets.js.map +1 -1
  63. package/dist/canvas/SceneCanvas/presets/arrange.js +35 -10
  64. package/dist/canvas/SceneCanvas/presets/arrange.js.map +1 -1
  65. package/dist/canvas/SceneCanvas/presets/baseline.js +9 -0
  66. package/dist/canvas/SceneCanvas/presets/baseline.js.map +1 -0
  67. package/dist/canvas/SceneCanvas/presets/chrome.js.map +1 -1
  68. package/dist/canvas/SceneCanvas/presets/composites.js +43 -0
  69. package/dist/canvas/SceneCanvas/presets/composites.js.map +1 -0
  70. package/dist/canvas/SceneCanvas/presets/edit.js +79 -26
  71. package/dist/canvas/SceneCanvas/presets/edit.js.map +1 -1
  72. package/dist/canvas/SceneCanvas/presets/ingest.js +1 -0
  73. package/dist/canvas/SceneCanvas/presets/ingest.js.map +1 -1
  74. package/dist/canvas/SceneCanvas/presets/paths.js +58 -16
  75. package/dist/canvas/SceneCanvas/presets/paths.js.map +1 -1
  76. package/dist/canvas/SceneCanvas/presets/select.js +4 -2
  77. package/dist/canvas/SceneCanvas/presets/select.js.map +1 -1
  78. package/dist/canvas/SceneCanvas/presets/tools.js +24 -0
  79. package/dist/canvas/SceneCanvas/presets/tools.js.map +1 -0
  80. package/dist/canvas/SceneCanvas/presets/transform.js +4 -0
  81. package/dist/canvas/SceneCanvas/presets/transform.js.map +1 -1
  82. package/dist/canvas/SceneCanvas/presets/view.js +3 -1
  83. package/dist/canvas/SceneCanvas/presets/view.js.map +1 -1
  84. package/dist/canvas/SceneCanvas/props.js.map +1 -1
  85. package/dist/canvas/SceneCanvas/shapeGeneratorProperties.js +1 -1
  86. package/dist/canvas/SceneCanvas/shapeGeneratorProperties.js.map +1 -1
  87. package/dist/canvas/SceneCanvas/toolRegistry.js +5 -4
  88. package/dist/canvas/SceneCanvas/toolRegistry.js.map +1 -1
  89. package/dist/canvas/SceneCanvas/useCanvasTools.js +26 -10
  90. package/dist/canvas/SceneCanvas/useCanvasTools.js.map +1 -1
  91. package/dist/canvas/SceneCanvas/useContributionRoles.js +17 -2
  92. package/dist/canvas/SceneCanvas/useContributionRoles.js.map +1 -1
  93. package/dist/canvas/SceneCanvas/useDepartureGhostLayer.js +5 -4
  94. package/dist/canvas/SceneCanvas/useDepartureGhostLayer.js.map +1 -1
  95. package/dist/canvas/SceneCanvas/useDispatcherOverlayLayer.js +1 -1
  96. package/dist/canvas/SceneCanvas/useNodeAtPoint.js.map +1 -1
  97. package/dist/canvas/SceneCanvas/useSceneCanvasLayers.js +9 -8
  98. package/dist/canvas/SceneCanvas/useSceneCanvasLayers.js.map +1 -1
  99. package/dist/canvas/SceneCanvas/useSceneCanvasPathEdit.js +2 -2
  100. package/dist/canvas/SceneCanvas/useSceneCanvasPathEdit.js.map +1 -1
  101. package/dist/canvas/SceneCanvas/useSceneCanvasTools.js +4 -1
  102. package/dist/canvas/SceneCanvas/useSceneCanvasTools.js.map +1 -1
  103. package/dist/canvas/SceneCanvas/useSceneChrome.js +7 -4
  104. package/dist/canvas/SceneCanvas/useSceneChrome.js.map +1 -1
  105. package/dist/canvas/SceneCanvas/useSceneGestureDispatcher.js +9 -9
  106. package/dist/canvas/SceneCanvas/useSceneGestureDispatcher.js.map +1 -1
  107. package/dist/canvas/SceneCanvas/useScenePicking.js +4 -7
  108. package/dist/canvas/SceneCanvas/useScenePicking.js.map +1 -1
  109. package/dist/canvas/SceneCanvas/useSceneRedrawSources.js +2 -1
  110. package/dist/canvas/SceneCanvas/useSceneRedrawSources.js.map +1 -1
  111. package/dist/canvas/SceneCanvas/useSceneSelectTool.js +6 -6
  112. package/dist/canvas/SceneCanvas/useSceneSelectTool.js.map +1 -1
  113. package/dist/canvas/SceneCanvas/useSceneStandardActions.js +2 -2
  114. package/dist/canvas/SceneCanvas/useSceneStandardActions.js.map +1 -1
  115. package/dist/canvas/SceneCanvas/useSelectionOverlayLayer.js +1 -1
  116. package/dist/canvas/SceneCanvas/useSelectionOverlayLayer.js.map +1 -1
  117. package/dist/canvas/SceneCanvas/useSurfaceViewInputs.js.map +1 -1
  118. package/dist/canvas/SceneCanvas/useToolKeybindings.js +2 -2
  119. package/dist/canvas/SceneCanvas/useToolKeybindings.js.map +1 -1
  120. package/dist/canvas/SceneCanvas/useViewportActions.js +5 -2
  121. package/dist/canvas/SceneCanvas/useViewportActions.js.map +1 -1
  122. package/dist/canvas/SceneCanvas/worldPointAt.js.map +1 -1
  123. package/dist/canvas/SceneCanvas.js +22 -11
  124. package/dist/canvas/SceneCanvas.js.map +1 -1
  125. package/dist/canvas/SceneViewCanvas.js +1 -0
  126. package/dist/canvas/SceneViewCanvas.js.map +1 -1
  127. package/dist/canvas/ViewMarker.js.map +1 -1
  128. package/dist/canvas/accentColor.js +14 -1
  129. package/dist/canvas/accentColor.js.map +1 -1
  130. package/dist/canvas/affordanceAt.js +2 -2
  131. package/dist/canvas/affordanceAt.js.map +1 -1
  132. package/dist/canvas/buildSceneLayer.js +1 -1
  133. package/dist/canvas/buildSceneLayer.js.map +1 -1
  134. package/dist/canvas/buildSceneTree.js +5 -3
  135. package/dist/canvas/buildSceneTree.js.map +1 -1
  136. package/dist/canvas/canvasRenderer.js +6 -2
  137. package/dist/canvas/canvasRenderer.js.map +1 -1
  138. package/dist/canvas/deps/editAnchors.js +4 -4
  139. package/dist/canvas/deps/editAnchors.js.map +1 -1
  140. package/dist/canvas/deps/enteredGroup.js +14 -5
  141. package/dist/canvas/deps/enteredGroup.js.map +1 -1
  142. package/dist/canvas/deps/ingestion.js +5 -1
  143. package/dist/canvas/deps/ingestion.js.map +1 -1
  144. package/dist/canvas/deps/insert.js.map +1 -1
  145. package/dist/canvas/deps/insertSite.js +5 -3
  146. package/dist/canvas/deps/insertSite.js.map +1 -1
  147. package/dist/canvas/deps/nodeAtPoint.js +1 -12
  148. package/dist/canvas/deps/nodeAtPoint.js.map +1 -1
  149. package/dist/canvas/deps/pathEditCommits.js +3 -3
  150. package/dist/canvas/deps/pathEditCommits.js.map +1 -1
  151. package/dist/canvas/deps/slice.js +16 -2
  152. package/dist/canvas/deps/slice.js.map +1 -1
  153. package/dist/canvas/deps/snap.js +5 -5
  154. package/dist/canvas/deps/snap.js.map +1 -1
  155. package/dist/canvas/deps/textEdit.js +5 -6
  156. package/dist/canvas/deps/textEdit.js.map +1 -1
  157. package/dist/canvas/derivedPath.js +8 -3
  158. package/dist/canvas/derivedPath.js.map +1 -1
  159. package/dist/canvas/getNodeAtPoint.js +2 -2
  160. package/dist/canvas/getNodeAtPoint.js.map +1 -1
  161. package/dist/canvas/insertPreviewExtent.js.map +1 -1
  162. package/dist/canvas/layerSlots.js.map +1 -1
  163. package/dist/canvas/nodeShapes/measurePainter.js +1 -1
  164. package/dist/canvas/nodeShapes/measurePainter.js.map +1 -1
  165. package/dist/canvas/nodeShapes/strokedBounds.js +5 -3
  166. package/dist/canvas/nodeShapes/strokedBounds.js.map +1 -1
  167. package/dist/canvas/overlayRoleStrokes.js +6 -0
  168. package/dist/canvas/overlayRoleStrokes.js.map +1 -1
  169. package/dist/canvas/pickIndex/scenePickIndex.js +10 -12
  170. package/dist/canvas/pickIndex/scenePickIndex.js.map +1 -1
  171. package/dist/canvas/sceneAdapter.js +10 -19
  172. package/dist/canvas/sceneAdapter.js.map +1 -1
  173. package/dist/canvas/sceneClipboard.js +17 -4
  174. package/dist/canvas/sceneClipboard.js.map +1 -1
  175. package/dist/canvas/sceneViewRender.js +7 -5
  176. package/dist/canvas/sceneViewRender.js.map +1 -1
  177. package/dist/canvas/surfaceContribution.js.map +1 -1
  178. package/dist/canvas/useCanvasPaint.js +12 -4
  179. package/dist/canvas/useCanvasPaint.js.map +1 -1
  180. package/dist/canvas/useHitObserver.js +1 -1
  181. package/dist/canvas/useHitObserver.js.map +1 -1
  182. package/dist/canvas/useViewAim.js +1 -1
  183. package/dist/canvas/useViewAim.js.map +1 -1
  184. package/dist/canvas/useViewHelpers.js +8 -5
  185. package/dist/canvas/useViewHelpers.js.map +1 -1
  186. package/dist/canvas/useViewNesting.js +39 -12
  187. package/dist/canvas/useViewNesting.js.map +1 -1
  188. package/dist/canvas/viewInputs.js.map +1 -1
  189. package/dist/canvas/viewMarkers.js +2 -2
  190. package/dist/canvas/viewMarkers.js.map +1 -1
  191. package/dist/canvas/viewRegistry.js +2 -2
  192. package/dist/canvas/viewRegistry.js.map +1 -1
  193. package/dist/canvas/viewSnap.js +67 -0
  194. package/dist/canvas/viewSnap.js.map +1 -0
  195. package/dist/clipboard.d.ts +6 -12
  196. package/dist/{clone-qb2e1F5p.d.ts → clone-Bz4iqGfE.d.ts} +10 -5
  197. package/dist/clone.d.ts +5 -5
  198. package/dist/core/geometry/booleanOfPaths.js +23 -0
  199. package/dist/core/geometry/booleanOfPaths.js.map +1 -0
  200. package/dist/core/geometry/pathPoseDescriptor.js +12 -9
  201. package/dist/core/geometry/pathPoseDescriptor.js.map +1 -1
  202. package/dist/core/geometry/poseDescriptor.js +12 -3
  203. package/dist/core/geometry/poseDescriptor.js.map +1 -1
  204. package/dist/core/geometry/targetFrame.js +2 -13
  205. package/dist/core/geometry/targetFrame.js.map +1 -1
  206. package/dist/core/layers/render.js +2 -1
  207. package/dist/core/layers/render.js.map +1 -1
  208. package/dist/core/layers/retain.js +5 -3
  209. package/dist/core/layers/retain.js.map +1 -1
  210. package/dist/core/ops/setPath.js +3 -0
  211. package/dist/core/ops/setPath.js.map +1 -1
  212. package/dist/core/paint/meshKindLazy.js.map +1 -1
  213. package/dist/core/paint/paintKindEntry.js.map +1 -1
  214. package/dist/core/paint/paintKinds.js +8 -1
  215. package/dist/core/paint/paintKinds.js.map +1 -1
  216. package/dist/core/scene/NodeProperties.js.map +1 -1
  217. package/dist/core/scene/NodeRouting.js.map +1 -1
  218. package/dist/core/scene/booleanGroup.js +33 -0
  219. package/dist/core/scene/booleanGroup.js.map +1 -0
  220. package/dist/core/scene/booleanOfChildren.js +53 -0
  221. package/dist/core/scene/booleanOfChildren.js.map +1 -0
  222. package/dist/core/scene/carryDescendants.js +18 -6
  223. package/dist/core/scene/carryDescendants.js.map +1 -1
  224. package/dist/core/scene/composeFrame.js +42 -5
  225. package/dist/core/scene/composeFrame.js.map +1 -1
  226. package/dist/core/scene/composePose.js +35 -16
  227. package/dist/core/scene/composePose.js.map +1 -1
  228. package/dist/core/scene/depMemo.js +36 -18
  229. package/dist/core/scene/depMemo.js.map +1 -1
  230. package/dist/core/scene/derivedParts.js +2 -23
  231. package/dist/core/scene/derivedParts.js.map +1 -1
  232. package/dist/core/scene/effectivePose.js +10 -0
  233. package/dist/core/scene/effectivePose.js.map +1 -1
  234. package/dist/core/scene/historyForm.js +5 -4
  235. package/dist/core/scene/historyForm.js.map +1 -1
  236. package/dist/core/scene/kitOps.js +5 -71
  237. package/dist/core/scene/kitOps.js.map +1 -1
  238. package/dist/core/scene/kitRegistry.js +5 -0
  239. package/dist/core/scene/kitRegistry.js.map +1 -1
  240. package/dist/core/scene/layerOps.js +82 -0
  241. package/dist/core/scene/layerOps.js.map +1 -0
  242. package/dist/core/scene/layoutPass.js +14 -12
  243. package/dist/core/scene/layoutPass.js.map +1 -1
  244. package/dist/core/scene/lockGuard.js +9 -3
  245. package/dist/core/scene/lockGuard.js.map +1 -1
  246. package/dist/core/scene/nestedHit.js +5 -5
  247. package/dist/core/scene/nestedHit.js.map +1 -1
  248. package/dist/core/scene/nodeFlags.js +8 -2
  249. package/dist/core/scene/nodeFlags.js.map +1 -1
  250. package/dist/core/scene/nodeGates.js +31 -2
  251. package/dist/core/scene/nodeGates.js.map +1 -1
  252. package/dist/core/scene/pathEffects/effects.js +22 -3
  253. package/dist/core/scene/pathEffects/effects.js.map +1 -1
  254. package/dist/core/scene/pathEffects/textAlong.js +16 -3
  255. package/dist/core/scene/pathEffects/textAlong.js.map +1 -1
  256. package/dist/core/scene/pathEffects/textAlongBands.js +65 -0
  257. package/dist/core/scene/pathEffects/textAlongBands.js.map +1 -0
  258. package/dist/core/scene/reconcileSpecs.js +1 -1
  259. package/dist/core/scene/reconcileSpecs.js.map +1 -1
  260. package/dist/core/scene/scene.js +11 -5
  261. package/dist/core/scene/scene.js.map +1 -1
  262. package/dist/core/scene/sceneEdits.js +5 -2
  263. package/dist/core/scene/sceneEdits.js.map +1 -1
  264. package/dist/core/scene/scenePoseAdapter.js +10 -1
  265. package/dist/core/scene/scenePoseAdapter.js.map +1 -1
  266. package/dist/core/scene/scrollOffsets.js +93 -0
  267. package/dist/core/scene/scrollOffsets.js.map +1 -0
  268. package/dist/core/scene/serialization.js +15 -5
  269. package/dist/core/scene/serialization.js.map +1 -1
  270. package/dist/core/scene/statedFields.js +2 -1
  271. package/dist/core/scene/statedFields.js.map +1 -1
  272. package/dist/core/scene/strategyView.js +35 -0
  273. package/dist/core/scene/strategyView.js.map +1 -0
  274. package/dist/core/scene/types.js.map +1 -1
  275. package/dist/core/scene/useScene.js +2 -0
  276. package/dist/core/scene/useScene.js.map +1 -1
  277. package/dist/core/scene/worldSave.js +87 -0
  278. package/dist/core/scene/worldSave.js.map +1 -0
  279. package/dist/core/selection/selectionTarget.js +1 -1
  280. package/dist/core/selection/selectionTarget.js.map +1 -1
  281. package/dist/{cornerHandles-CNCb7aTY.d.ts → cornerHandles-DpmQM_z5.d.ts} +1 -1
  282. package/dist/{depSchema-B1RS-IJx.d.ts → depSchema-C3BwxitB.d.ts} +130 -104
  283. package/dist/devtools-protocol.d.ts +2 -2
  284. package/dist/devtools.d.ts +2 -2
  285. package/dist/{features → domains}/chrome-caps/buildChromeCtx.js +1 -1
  286. package/dist/domains/chrome-caps/buildChromeCtx.js.map +1 -0
  287. package/dist/{features → domains}/chrome-caps/conditions.js +1 -1
  288. package/dist/domains/chrome-caps/conditions.js.map +1 -0
  289. package/dist/{features → domains}/chrome-caps/defaults.js +1 -1
  290. package/dist/domains/chrome-caps/defaults.js.map +1 -0
  291. package/dist/{features → domains}/chrome-caps/resolve.js +1 -1
  292. package/dist/domains/chrome-caps/resolve.js.map +1 -0
  293. package/dist/{features → domains}/chrome-caps/useChromeCaps.js +1 -1
  294. package/dist/domains/chrome-caps/useChromeCaps.js.map +1 -0
  295. package/dist/{features → domains}/chrome-caps/useHoverTracking.js +1 -1
  296. package/dist/domains/chrome-caps/useHoverTracking.js.map +1 -0
  297. package/dist/{features → domains}/ingestion/contentHandlers.js +20 -3
  298. package/dist/domains/ingestion/contentHandlers.js.map +1 -0
  299. package/dist/domains/ingestion/ghost.js +56 -0
  300. package/dist/domains/ingestion/ghost.js.map +1 -0
  301. package/dist/{features → domains}/ingestion/imageHandler.js +1 -1
  302. package/dist/domains/ingestion/imageHandler.js.map +1 -0
  303. package/dist/domains/ingestion/kitHandlers.js +22 -0
  304. package/dist/domains/ingestion/kitHandlers.js.map +1 -0
  305. package/dist/{features → domains}/ingestion/openFilePicker.js +1 -1
  306. package/dist/domains/ingestion/openFilePicker.js.map +1 -0
  307. package/dist/{features → domains}/ingestion/placement.js +1 -1
  308. package/dist/domains/ingestion/placement.js.map +1 -0
  309. package/dist/{features → domains}/ingestion/svgHandler.js +1 -1
  310. package/dist/domains/ingestion/svgHandler.js.map +1 -0
  311. package/dist/{features → domains}/ingestion/textHandler.js +9 -7
  312. package/dist/domains/ingestion/textHandler.js.map +1 -0
  313. package/dist/{features → domains}/ingestion/useCanvasIngestion.js +13 -15
  314. package/dist/domains/ingestion/useCanvasIngestion.js.map +1 -0
  315. package/dist/{features → domains}/ingestion/weaselJsonHandler.js +1 -1
  316. package/dist/domains/ingestion/weaselJsonHandler.js.map +1 -0
  317. package/dist/{features → domains}/longPress/longPressFeedback.js +1 -1
  318. package/dist/domains/longPress/longPressFeedback.js.map +1 -0
  319. package/dist/{features → domains}/measure/actionIds.js +1 -1
  320. package/dist/domains/measure/actionIds.js.map +1 -0
  321. package/dist/{features → domains}/measure/measureCommands.js +1 -1
  322. package/dist/domains/measure/measureCommands.js.map +1 -0
  323. package/dist/{features → domains}/measure/measureContribution.js +1 -1
  324. package/dist/domains/measure/measureContribution.js.map +1 -0
  325. package/dist/{features → domains}/measure/measureEdits.js +1 -1
  326. package/dist/domains/measure/measureEdits.js.map +1 -0
  327. package/dist/{features → domains}/measure/measureGestures.js +4 -7
  328. package/dist/domains/measure/measureGestures.js.map +1 -0
  329. package/dist/{features → domains}/measure/measureHit.js +1 -1
  330. package/dist/domains/measure/measureHit.js.map +1 -0
  331. package/dist/{features → domains}/measure/measureLayer.js +1 -1
  332. package/dist/domains/measure/measureLayer.js.map +1 -0
  333. package/dist/{features → domains}/measure/measurement.js +1 -1
  334. package/dist/domains/measure/measurement.js.map +1 -0
  335. package/dist/{features → domains}/measure/measurements.js +2 -2
  336. package/dist/domains/measure/measurements.js.map +1 -0
  337. package/dist/{features → domains}/modes/modeLayers.js +1 -1
  338. package/dist/domains/modes/modeLayers.js.map +1 -0
  339. package/dist/{features → domains}/modes/modeTriggers.js +3 -6
  340. package/dist/domains/modes/modeTriggers.js.map +1 -0
  341. package/dist/{features → domains}/pathEffects/effectSources.js +1 -1
  342. package/dist/domains/pathEffects/effectSources.js.map +1 -0
  343. package/dist/{features → domains}/pathEffects/index.js +1 -1
  344. package/dist/domains/pathEffects/index.js.map +1 -0
  345. package/dist/{features → domains}/pathEffects/readSource.js +1 -1
  346. package/dist/domains/pathEffects/readSource.js.map +1 -0
  347. package/dist/{features → domains}/pathEffects/textItems.js +11 -2
  348. package/dist/domains/pathEffects/textItems.js.map +1 -0
  349. package/dist/{features → domains}/pathEffects/useEffectSourcesLayer.js +1 -1
  350. package/dist/domains/pathEffects/useEffectSourcesLayer.js.map +1 -0
  351. package/dist/{features → domains}/paths/anchorData.js +1 -1
  352. package/dist/domains/paths/anchorData.js.map +1 -0
  353. package/dist/{features → domains}/paths/anchorMarkers.js +9 -7
  354. package/dist/domains/paths/anchorMarkers.js.map +1 -0
  355. package/dist/{features → domains}/paths/editablePath.js +1 -1
  356. package/dist/domains/paths/editablePath.js.map +1 -0
  357. package/dist/{features → domains}/paths/index.js +3 -3
  358. package/dist/{features → domains}/paths/originProjection.js +1 -1
  359. package/dist/domains/paths/originProjection.js.map +1 -0
  360. package/dist/{features → domains}/paths/pathEditExtension.js +1 -1
  361. package/dist/domains/paths/pathEditExtension.js.map +1 -0
  362. package/dist/{features → domains}/paths/pathEditState.js +1 -1
  363. package/dist/domains/paths/pathEditState.js.map +1 -0
  364. package/dist/{features → domains}/paths/pathEditingOverlayLayer.js +1 -1
  365. package/dist/domains/paths/pathEditingOverlayLayer.js.map +1 -0
  366. package/dist/{features → domains}/paths/pathLayer.js +1 -1
  367. package/dist/domains/paths/pathLayer.js.map +1 -0
  368. package/dist/{features → domains}/paths/pathRepresentation.js +1 -1
  369. package/dist/domains/paths/pathRepresentation.js.map +1 -0
  370. package/dist/{features → domains}/paths/pathSnap/glyphs.js +1 -1
  371. package/dist/domains/paths/pathSnap/glyphs.js.map +1 -0
  372. package/dist/{features → domains}/paths/pathSnap/pathSnapSource.js +1 -1
  373. package/dist/domains/paths/pathSnap/pathSnapSource.js.map +1 -0
  374. package/dist/{features → domains}/paths/pathSnap/sceneIndex.js +1 -1
  375. package/dist/domains/paths/pathSnap/sceneIndex.js.map +1 -0
  376. package/dist/{features → domains}/paths/pathSnap/snapGeometry.js +3 -2
  377. package/dist/domains/paths/pathSnap/snapGeometry.js.map +1 -0
  378. package/dist/{features → domains}/paths/penPreviewLayer.js +1 -1
  379. package/dist/domains/paths/penPreviewLayer.js.map +1 -0
  380. package/dist/{features → domains}/paths/shapeGenerator.js +6 -4
  381. package/dist/domains/paths/shapeGenerator.js.map +1 -0
  382. package/dist/{features → domains}/paths/strokeOutline.js +1 -1
  383. package/dist/domains/paths/strokeOutline.js.map +1 -0
  384. package/dist/{features → domains}/paths/useAnchorFields.js +1 -1
  385. package/dist/domains/paths/useAnchorFields.js.map +1 -0
  386. package/dist/{features → domains}/paths/usePathEdit.js +1 -1
  387. package/dist/domains/paths/usePathEdit.js.map +1 -0
  388. package/dist/{features → domains}/poseRun/usePoseRun.js +1 -1
  389. package/dist/domains/poseRun/usePoseRun.js.map +1 -0
  390. package/dist/{features → domains}/selection/enteredGroupFrame.js +49 -10
  391. package/dist/domains/selection/enteredGroupFrame.js.map +1 -0
  392. package/dist/{features → domains}/selection/enteredGroupScope.js +1 -1
  393. package/dist/domains/selection/enteredGroupScope.js.map +1 -0
  394. package/dist/domains/selection/enteredOperands.js +29 -0
  395. package/dist/domains/selection/enteredOperands.js.map +1 -0
  396. package/dist/{features → domains}/selection/handleCommands.js +1 -1
  397. package/dist/domains/selection/handleCommands.js.map +1 -0
  398. package/dist/{features → domains}/selection/overlay.js +1 -1
  399. package/dist/domains/selection/overlay.js.map +1 -0
  400. package/dist/{features → domains}/selection/selectionPose.js +1 -1
  401. package/dist/domains/selection/selectionPose.js.map +1 -0
  402. package/dist/{features → domains}/snap/angle2d.js +1 -1
  403. package/dist/domains/snap/angle2d.js.map +1 -0
  404. package/dist/{features → domains}/snap/debugCandidates.js +1 -1
  405. package/dist/domains/snap/debugCandidates.js.map +1 -0
  406. package/dist/{features → domains}/snap/gather.js +1 -1
  407. package/dist/domains/snap/gather.js.map +1 -0
  408. package/dist/{features → domains}/snap/inputSubspace.js +1 -1
  409. package/dist/domains/snap/inputSubspace.js.map +1 -0
  410. package/dist/{features → domains}/snap/lazySession.js +1 -1
  411. package/dist/domains/snap/lazySession.js.map +1 -0
  412. package/dist/{features → domains}/snap/marks.js +1 -1
  413. package/dist/domains/snap/marks.js.map +1 -0
  414. package/dist/{features → domains}/snap/outcomeStore.js +1 -1
  415. package/dist/domains/snap/outcomeStore.js.map +1 -0
  416. package/dist/{features → domains}/snap/pointSnap.js +1 -1
  417. package/dist/domains/snap/pointSnap.js.map +1 -0
  418. package/dist/{features → domains}/snap/probes2d.js +1 -1
  419. package/dist/domains/snap/probes2d.js.map +1 -0
  420. package/dist/{features → domains}/snap/readoutDraw.js +1 -1
  421. package/dist/domains/snap/readoutDraw.js.map +1 -0
  422. package/dist/{features → domains}/snap/readoutLayer.js +1 -1
  423. package/dist/domains/snap/readoutLayer.js.map +1 -0
  424. package/dist/{features → domains}/snap/registry.js +1 -1
  425. package/dist/domains/snap/registry.js.map +1 -0
  426. package/dist/{features → domains}/snap/resizeBox.js +1 -1
  427. package/dist/domains/snap/resizeBox.js.map +1 -0
  428. package/dist/{features → domains}/snap/roles.js +1 -1
  429. package/dist/domains/snap/roles.js.map +1 -0
  430. package/dist/{features → domains}/snap/rotationSource.js +1 -1
  431. package/dist/domains/snap/rotationSource.js.map +1 -0
  432. package/dist/{features → domains}/snap/sceneReads.js +24 -3
  433. package/dist/domains/snap/sceneReads.js.map +1 -0
  434. package/dist/{features → domains}/snap/sceneSession2d.js +3 -2
  435. package/dist/domains/snap/sceneSession2d.js.map +1 -0
  436. package/dist/{features → domains}/snap/screen.js +1 -1
  437. package/dist/domains/snap/screen.js.map +1 -0
  438. package/dist/{features → domains}/snap/session2d.js +3 -2
  439. package/dist/domains/snap/session2d.js.map +1 -0
  440. package/dist/{features → domains}/snap/spanSnap.js +1 -1
  441. package/dist/domains/snap/spanSnap.js.map +1 -0
  442. package/dist/{features → domains}/snap/stepAngles.js +1 -1
  443. package/dist/domains/snap/stepAngles.js.map +1 -0
  444. package/dist/{features → domains}/text/editingDrawOne.js +4 -4
  445. package/dist/domains/text/editingDrawOne.js.map +1 -0
  446. package/dist/domains/text/hostTextEditors.js +24 -0
  447. package/dist/domains/text/hostTextEditors.js.map +1 -0
  448. package/dist/{features → domains}/text/index.js +1 -1
  449. package/dist/{features → domains}/text/sceneTextDrafts.js +1 -1
  450. package/dist/domains/text/sceneTextDrafts.js.map +1 -0
  451. package/dist/{features → domains}/text/textHitAt.js +18 -2
  452. package/dist/domains/text/textHitAt.js.map +1 -0
  453. package/dist/{features → domains}/text/textLayer.js +1 -1
  454. package/dist/domains/text/textLayer.js.map +1 -0
  455. package/dist/{features → domains}/text/useSceneTextEdit.js +11 -3
  456. package/dist/domains/text/useSceneTextEdit.js.map +1 -0
  457. package/dist/{features → domains}/viewports/aim.js +1 -1
  458. package/dist/domains/viewports/aim.js.map +1 -0
  459. package/dist/{features → domains}/viewports/viewMarker.js +23 -5
  460. package/dist/domains/viewports/viewMarker.js.map +1 -0
  461. package/dist/{features → domains}/viewports/viewMarkerDrag.js +3 -3
  462. package/dist/domains/viewports/viewMarkerDrag.js.map +1 -0
  463. package/dist/{features → domains}/viewports/viewResolver.js +1 -1
  464. package/dist/domains/viewports/viewResolver.js.map +1 -0
  465. package/dist/{features → domains}/viewports/viewportLayer.js +3 -2
  466. package/dist/domains/viewports/viewportLayer.js.map +1 -0
  467. package/dist/icons.table.js +1 -1
  468. package/dist/icons.table.js.map +1 -1
  469. package/dist/icons.table.json +106 -6
  470. package/dist/index.d.ts +1445 -1053
  471. package/dist/index.js +90 -77
  472. package/dist/interactions/actions/admitsChild.js +6 -2
  473. package/dist/interactions/actions/admitsChild.js.map +1 -1
  474. package/dist/interactions/actions/align/align.js +1 -4
  475. package/dist/interactions/actions/align/align.js.map +1 -1
  476. package/dist/interactions/actions/booleans/booleanGroupAction.js +66 -0
  477. package/dist/interactions/actions/booleans/booleanGroupAction.js.map +1 -0
  478. package/dist/interactions/actions/booleans/keymap.js +52 -0
  479. package/dist/interactions/actions/booleans/keymap.js.map +1 -0
  480. package/dist/interactions/actions/booleans/operands.js +1 -1
  481. package/dist/interactions/actions/booleans/pieces.js +4 -11
  482. package/dist/interactions/actions/booleans/pieces.js.map +1 -1
  483. package/dist/interactions/actions/clipboard/action.js +3 -7
  484. package/dist/interactions/actions/clipboard/action.js.map +1 -1
  485. package/dist/interactions/actions/clipboard/clipboardOps.js +1 -1
  486. package/dist/interactions/actions/clipboard/clipboardOps.js.map +1 -1
  487. package/dist/interactions/actions/clipboard/materializePaste.js.map +1 -1
  488. package/dist/interactions/actions/defaults/anchorEditing.js +6 -6
  489. package/dist/interactions/actions/defaults/anchorEditing.js.map +1 -1
  490. package/dist/interactions/actions/defaults/bendSegment.js +1 -1
  491. package/dist/interactions/actions/defaults/bendSegment.js.map +1 -1
  492. package/dist/interactions/actions/defaults/containerScroll.js +170 -0
  493. package/dist/interactions/actions/defaults/containerScroll.js.map +1 -0
  494. package/dist/interactions/actions/defaults/contextMenu.js +2 -5
  495. package/dist/interactions/actions/defaults/contextMenu.js.map +1 -1
  496. package/dist/interactions/actions/defaults/delete.js +1 -1
  497. package/dist/interactions/actions/defaults/delete.js.map +1 -1
  498. package/dist/interactions/actions/defaults/duplicate.js +1 -3
  499. package/dist/interactions/actions/defaults/duplicate.js.map +1 -1
  500. package/dist/interactions/actions/defaults/enterGroup.js +7 -12
  501. package/dist/interactions/actions/defaults/enterGroup.js.map +1 -1
  502. package/dist/interactions/actions/defaults/enterPathEdit.js +4 -8
  503. package/dist/interactions/actions/defaults/enterPathEdit.js.map +1 -1
  504. package/dist/interactions/actions/defaults/group.js +12 -24
  505. package/dist/interactions/actions/defaults/group.js.map +1 -1
  506. package/dist/interactions/actions/defaults/ingest.js +18 -10
  507. package/dist/interactions/actions/defaults/ingest.js.map +1 -1
  508. package/dist/interactions/actions/defaults/insertPathAnchor.js +3 -3
  509. package/dist/interactions/actions/defaults/insertPathAnchor.js.map +1 -1
  510. package/dist/interactions/actions/defaults/nudgeSteps.js +3 -21
  511. package/dist/interactions/actions/defaults/nudgeSteps.js.map +1 -1
  512. package/dist/interactions/actions/defaults/pathEditMarks.js.map +1 -1
  513. package/dist/interactions/actions/defaults/selectDeep.js +2 -2
  514. package/dist/interactions/actions/defaults/selectDeep.js.map +1 -1
  515. package/dist/interactions/actions/distribute/distribute.js.map +1 -1
  516. package/dist/interactions/actions/dropVerdict.js +9 -0
  517. package/dist/interactions/actions/dropVerdict.js.map +1 -0
  518. package/dist/interactions/actions/edit-anchors/action.js +2 -2
  519. package/dist/interactions/actions/edit-anchors/action.js.map +1 -1
  520. package/dist/interactions/actions/edit-anchors/extensionDrags.js.map +1 -1
  521. package/dist/interactions/actions/edit-anchors/geometry.js +8 -6
  522. package/dist/interactions/actions/edit-anchors/geometry.js.map +1 -1
  523. package/dist/interactions/actions/edit-anchors/handleDrag.js.map +1 -1
  524. package/dist/interactions/actions/edit-anchors/preview.js +1 -1
  525. package/dist/interactions/actions/edit-anchors/preview.js.map +1 -1
  526. package/dist/interactions/actions/flip/action.js +3 -2
  527. package/dist/interactions/actions/flip/action.js.map +1 -1
  528. package/dist/interactions/actions/geometryProjection.js +8 -3
  529. package/dist/interactions/actions/geometryProjection.js.map +1 -1
  530. package/dist/interactions/actions/gestureFrames.js +1 -0
  531. package/dist/interactions/actions/gestureFrames.js.map +1 -1
  532. package/dist/interactions/actions/insert/action.js +6 -2
  533. package/dist/interactions/actions/insert/action.js.map +1 -1
  534. package/dist/interactions/actions/insert/frame.js +1 -1
  535. package/dist/interactions/actions/insert/frame.js.map +1 -1
  536. package/dist/interactions/actions/insert/placeAction.js +6 -8
  537. package/dist/interactions/actions/insert/placeAction.js.map +1 -1
  538. package/dist/interactions/actions/insert/session.js +2 -2
  539. package/dist/interactions/actions/insert/session.js.map +1 -1
  540. package/dist/interactions/actions/move/action.js +6 -15
  541. package/dist/interactions/actions/move/action.js.map +1 -1
  542. package/dist/interactions/actions/move/behaviors/layoutDrop.js +12 -2
  543. package/dist/interactions/actions/move/behaviors/layoutDrop.js.map +1 -1
  544. package/dist/interactions/actions/move/behaviors/reparentOnDrop.js +29 -10
  545. package/dist/interactions/actions/move/behaviors/reparentOnDrop.js.map +1 -1
  546. package/dist/interactions/actions/move/behaviors/snapToContainer.js +42 -6
  547. package/dist/interactions/actions/move/behaviors/snapToContainer.js.map +1 -1
  548. package/dist/interactions/actions/move/capture.js +4 -8
  549. package/dist/interactions/actions/move/capture.js.map +1 -1
  550. package/dist/interactions/actions/move/commit/index.js.map +1 -1
  551. package/dist/interactions/actions/move/commit/layoutDrop.js +4 -3
  552. package/dist/interactions/actions/move/commit/layoutDrop.js.map +1 -1
  553. package/dist/interactions/actions/move/commit/layoutRelease.js +15 -9
  554. package/dist/interactions/actions/move/commit/layoutRelease.js.map +1 -1
  555. package/dist/interactions/actions/move/commit/reparent.js +19 -13
  556. package/dist/interactions/actions/move/commit/reparent.js.map +1 -1
  557. package/dist/interactions/actions/move/delta.js +51 -5
  558. package/dist/interactions/actions/move/delta.js.map +1 -1
  559. package/dist/interactions/actions/move/frame.js +8 -4
  560. package/dist/interactions/actions/move/frame.js.map +1 -1
  561. package/dist/interactions/actions/move/layout/container.js +19 -9
  562. package/dist/interactions/actions/move/layout/container.js.map +1 -1
  563. package/dist/interactions/actions/move/layout/dragged.js +2 -2
  564. package/dist/interactions/actions/move/layout/dragged.js.map +1 -1
  565. package/dist/interactions/actions/move/layout/dropPass.js +36 -18
  566. package/dist/interactions/actions/move/layout/dropPass.js.map +1 -1
  567. package/dist/interactions/actions/move/layout/exits.js +2 -2
  568. package/dist/interactions/actions/move/layout/exits.js.map +1 -1
  569. package/dist/interactions/actions/move/layout/glide.js +5 -5
  570. package/dist/interactions/actions/move/layout/glide.js.map +1 -1
  571. package/dist/interactions/actions/move/layout/view.js +55 -0
  572. package/dist/interactions/actions/move/layout/view.js.map +1 -0
  573. package/dist/interactions/actions/move/refusal.js +52 -0
  574. package/dist/interactions/actions/move/refusal.js.map +1 -0
  575. package/dist/interactions/actions/move/session.js +9 -8
  576. package/dist/interactions/actions/move/session.js.map +1 -1
  577. package/dist/interactions/actions/move/translate.js +10 -4
  578. package/dist/interactions/actions/move/translate.js.map +1 -1
  579. package/dist/interactions/actions/moveNodes.js +21 -5
  580. package/dist/interactions/actions/moveNodes.js.map +1 -1
  581. package/dist/interactions/actions/pathCommands/pathNodes.js +3 -3
  582. package/dist/interactions/actions/pathCommands/pathNodes.js.map +1 -1
  583. package/dist/interactions/actions/planeInput.js +14 -13
  584. package/dist/interactions/actions/planeInput.js.map +1 -1
  585. package/dist/interactions/actions/poseFrame.js +21 -8
  586. package/dist/interactions/actions/poseFrame.js.map +1 -1
  587. package/dist/interactions/actions/resize/action.js +1 -1
  588. package/dist/interactions/actions/resize/action.js.map +1 -1
  589. package/dist/interactions/actions/resize/aspect.js +1 -1
  590. package/dist/interactions/actions/resize/aspect.js.map +1 -1
  591. package/dist/interactions/actions/resize/commit.js +10 -1
  592. package/dist/interactions/actions/resize/commit.js.map +1 -1
  593. package/dist/interactions/actions/resize/frame.js +3 -2
  594. package/dist/interactions/actions/resize/frame.js.map +1 -1
  595. package/dist/interactions/actions/resize/held.js +44 -0
  596. package/dist/interactions/actions/resize/held.js.map +1 -0
  597. package/dist/interactions/actions/resize/session.js +3 -1
  598. package/dist/interactions/actions/resize/session.js.map +1 -1
  599. package/dist/interactions/actions/resolveOverlays.js +9 -0
  600. package/dist/interactions/actions/resolveOverlays.js.map +1 -1
  601. package/dist/interactions/actions/resolvePreviews.js +23 -7
  602. package/dist/interactions/actions/resolvePreviews.js.map +1 -1
  603. package/dist/interactions/actions/rotate/action.js +1 -1
  604. package/dist/interactions/actions/rotate/action.js.map +1 -1
  605. package/dist/interactions/actions/rotate/frame.js +1 -1
  606. package/dist/interactions/actions/rotate/frame.js.map +1 -1
  607. package/dist/interactions/actions/rotate/session.js +2 -2
  608. package/dist/interactions/actions/rotate/session.js.map +1 -1
  609. package/dist/interactions/actions/selectionSubtree.js +2 -4
  610. package/dist/interactions/actions/selectionSubtree.js.map +1 -1
  611. package/dist/interactions/actions/spatialReference.js +4 -9
  612. package/dist/interactions/actions/spatialReference.js.map +1 -1
  613. package/dist/interactions/gestures/dragRadial/dragRadial.js.map +1 -1
  614. package/dist/interactions/gestures/dragRect/dragRect.js.map +1 -1
  615. package/dist/kitSettingsSchema.js +2 -2
  616. package/dist/kitSettingsSchema.js.map +1 -1
  617. package/dist/{math-C_elShP_.d.ts → math-B_unOnF4.d.ts} +2 -2
  618. package/dist/math.d.ts +3 -3
  619. package/dist/move.d.ts +6 -6
  620. package/dist/{options-ClEm3SEl.d.ts → options-DAjkhbcs.d.ts} +5 -5
  621. package/dist/{poseDescriptor-DN2yfnq_.d.ts → poseDescriptor-CvSxVhCd.d.ts} +17 -4
  622. package/dist/resize.d.ts +6 -6
  623. package/dist/style.css +14 -0
  624. package/dist/test-seams.d.ts +11 -15
  625. package/dist/test-seams.js +1 -1
  626. package/dist/tools/builtin/eyedropper/useEyedropperTool.js +3 -6
  627. package/dist/tools/builtin/eyedropper/useEyedropperTool.js.map +1 -1
  628. package/dist/tools/builtin/line/useLineTool.js.map +1 -1
  629. package/dist/tools/builtin/measure/useMeasureTool.js +2 -2
  630. package/dist/tools/builtin/measure/useMeasureTool.js.map +1 -1
  631. package/dist/tools/builtin/pen/penHandle.js +2 -2
  632. package/dist/tools/builtin/pen/penHandle.js.map +1 -1
  633. package/dist/tools/builtin/pen/usePenTool.js +13 -19
  634. package/dist/tools/builtin/pen/usePenTool.js.map +1 -1
  635. package/dist/tools/builtin/polygon/usePolygonTool.js +1 -1
  636. package/dist/tools/builtin/polygon/usePolygonTool.js.map +1 -1
  637. package/dist/tools/builtin/select/groupEntry.js +1 -1
  638. package/dist/tools/builtin/select/groupEntry.js.map +1 -1
  639. package/dist/tools/builtin/select/selectionContributions.js +1 -1
  640. package/dist/tools/builtin/select/selectionContributions.js.map +1 -1
  641. package/dist/tools/builtin/select/useSelectTool.js +7 -7
  642. package/dist/tools/builtin/select/useSelectTool.js.map +1 -1
  643. package/dist/tools/builtin/slice/useSliceTool.js +5 -8
  644. package/dist/tools/builtin/slice/useSliceTool.js.map +1 -1
  645. package/dist/tools/builtin/star/useStarTool.js +1 -1
  646. package/dist/tools/builtin/star/useStarTool.js.map +1 -1
  647. package/dist/tools/index.js +2 -1
  648. package/dist/{types-49uYJN3j.d.ts → types-A_sNJYRd.d.ts} +8 -0
  649. package/dist/{types-BEdRIhNc.d.ts → types-DW14eu9B.d.ts} +131 -36
  650. package/dist/{types-p2alu-R1.d.ts → types-VCtfchp-.d.ts} +4 -6
  651. package/dist/util/color.js +12 -14
  652. package/dist/util/color.js.map +1 -1
  653. package/dist/version.js +1 -1
  654. package/package.json +25 -24
  655. package/dist/canvas/poseCascade.js +0 -65
  656. package/dist/canvas/poseCascade.js.map +0 -1
  657. package/dist/features/chrome-caps/buildChromeCtx.js.map +0 -1
  658. package/dist/features/chrome-caps/conditions.js.map +0 -1
  659. package/dist/features/chrome-caps/defaults.js.map +0 -1
  660. package/dist/features/chrome-caps/resolve.js.map +0 -1
  661. package/dist/features/chrome-caps/useChromeCaps.js.map +0 -1
  662. package/dist/features/chrome-caps/useHoverTracking.js.map +0 -1
  663. package/dist/features/ingestion/contentHandlers.js.map +0 -1
  664. package/dist/features/ingestion/imageHandler.js.map +0 -1
  665. package/dist/features/ingestion/openFilePicker.js.map +0 -1
  666. package/dist/features/ingestion/placement.js.map +0 -1
  667. package/dist/features/ingestion/registerKitHandlers.js +0 -43
  668. package/dist/features/ingestion/registerKitHandlers.js.map +0 -1
  669. package/dist/features/ingestion/svgHandler.js.map +0 -1
  670. package/dist/features/ingestion/textHandler.js.map +0 -1
  671. package/dist/features/ingestion/useCanvasIngestion.js.map +0 -1
  672. package/dist/features/ingestion/weaselJsonHandler.js.map +0 -1
  673. package/dist/features/longPress/longPressFeedback.js.map +0 -1
  674. package/dist/features/measure/actionIds.js.map +0 -1
  675. package/dist/features/measure/measureCommands.js.map +0 -1
  676. package/dist/features/measure/measureContribution.js.map +0 -1
  677. package/dist/features/measure/measureEdits.js.map +0 -1
  678. package/dist/features/measure/measureGestures.js.map +0 -1
  679. package/dist/features/measure/measureHit.js.map +0 -1
  680. package/dist/features/measure/measureLayer.js.map +0 -1
  681. package/dist/features/measure/measurement.js.map +0 -1
  682. package/dist/features/measure/measurements.js.map +0 -1
  683. package/dist/features/modes/modeLayers.js.map +0 -1
  684. package/dist/features/modes/modeTriggers.js.map +0 -1
  685. package/dist/features/pathEffects/effectSources.js.map +0 -1
  686. package/dist/features/pathEffects/index.js.map +0 -1
  687. package/dist/features/pathEffects/readSource.js.map +0 -1
  688. package/dist/features/pathEffects/textItems.js.map +0 -1
  689. package/dist/features/pathEffects/useEffectSourcesLayer.js.map +0 -1
  690. package/dist/features/paths/anchorData.js.map +0 -1
  691. package/dist/features/paths/anchorMarkers.js.map +0 -1
  692. package/dist/features/paths/editablePath.js.map +0 -1
  693. package/dist/features/paths/originProjection.js.map +0 -1
  694. package/dist/features/paths/pathEditExtension.js.map +0 -1
  695. package/dist/features/paths/pathEditState.js.map +0 -1
  696. package/dist/features/paths/pathEditingOverlayLayer.js.map +0 -1
  697. package/dist/features/paths/pathLayer.js.map +0 -1
  698. package/dist/features/paths/pathRepresentation.js.map +0 -1
  699. package/dist/features/paths/pathSnap/glyphs.js.map +0 -1
  700. package/dist/features/paths/pathSnap/pathSnapSource.js.map +0 -1
  701. package/dist/features/paths/pathSnap/sceneIndex.js.map +0 -1
  702. package/dist/features/paths/pathSnap/snapGeometry.js.map +0 -1
  703. package/dist/features/paths/penPreviewLayer.js.map +0 -1
  704. package/dist/features/paths/shapeGenerator.js.map +0 -1
  705. package/dist/features/paths/strokeOutline.js.map +0 -1
  706. package/dist/features/paths/useAnchorFields.js.map +0 -1
  707. package/dist/features/paths/usePathEdit.js.map +0 -1
  708. package/dist/features/poseRun/usePoseRun.js.map +0 -1
  709. package/dist/features/selection/enteredGroupFrame.js.map +0 -1
  710. package/dist/features/selection/enteredGroupScope.js.map +0 -1
  711. package/dist/features/selection/handleCommands.js.map +0 -1
  712. package/dist/features/selection/overlay.js.map +0 -1
  713. package/dist/features/selection/selectionPose.js.map +0 -1
  714. package/dist/features/snap/angle2d.js.map +0 -1
  715. package/dist/features/snap/debugCandidates.js.map +0 -1
  716. package/dist/features/snap/gather.js.map +0 -1
  717. package/dist/features/snap/inputSubspace.js.map +0 -1
  718. package/dist/features/snap/lazySession.js.map +0 -1
  719. package/dist/features/snap/marks.js.map +0 -1
  720. package/dist/features/snap/outcomeStore.js.map +0 -1
  721. package/dist/features/snap/pointSnap.js.map +0 -1
  722. package/dist/features/snap/probes2d.js.map +0 -1
  723. package/dist/features/snap/readoutDraw.js.map +0 -1
  724. package/dist/features/snap/readoutLayer.js.map +0 -1
  725. package/dist/features/snap/registry.js.map +0 -1
  726. package/dist/features/snap/resizeBox.js.map +0 -1
  727. package/dist/features/snap/roles.js.map +0 -1
  728. package/dist/features/snap/rotationSource.js.map +0 -1
  729. package/dist/features/snap/sceneReads.js.map +0 -1
  730. package/dist/features/snap/sceneSession2d.js.map +0 -1
  731. package/dist/features/snap/screen.js.map +0 -1
  732. package/dist/features/snap/session2d.js.map +0 -1
  733. package/dist/features/snap/spanSnap.js.map +0 -1
  734. package/dist/features/snap/stepAngles.js.map +0 -1
  735. package/dist/features/text/editingDrawOne.js.map +0 -1
  736. package/dist/features/text/sceneTextDrafts.js.map +0 -1
  737. package/dist/features/text/textHitAt.js.map +0 -1
  738. package/dist/features/text/textLayer.js.map +0 -1
  739. package/dist/features/text/useSceneTextEdit.js.map +0 -1
  740. package/dist/features/viewports/aim.js.map +0 -1
  741. package/dist/features/viewports/viewMarker.js.map +0 -1
  742. package/dist/features/viewports/viewMarkerDrag.js.map +0 -1
  743. package/dist/features/viewports/viewResolver.js.map +0 -1
  744. package/dist/features/viewports/viewportLayer.js.map +0 -1
  745. /package/dist/{features → domains}/chrome-caps/index.js +0 -0
@@ -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 { 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 { useEnteredGroupFrameLayer } from 'features/selection/enteredGroupFrame';\nimport type { EnteredGroupApi } from '../deps/enteredGroup';\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; enteredGroup: EnteredGroupApi; frameColor: { read: () => string; changed: (fn: () => void) => () => void };\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 enteredFrameLayer = useEnteredGroupFrameLayer(args.enteredGroup, args.boundsOf, args.frameColor);\n const layers = useMemo<CanvasLayers>(() => ({\n ...builtLayersOf(merged),\n scene: sceneLayers,\n selectionOverlay: selectionOverlayLayer ? { layer: selectionOverlayLayer } : null,\n enteredGroupFrame: { layer: enteredFrameLayer, before: 'selectionOverlay' },\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 }), [merged, sceneLayers, selectionOverlayLayer, enteredFrameLayer, departureLayer, previewLayer, effectSourcesLayer, dispatcherOverlay, pathEditingOverlayLayer, overlaySlot, overlayAnchor, snapReadoutLayer, args.snapReadout, slops, slopsLayer,\n ]);\n\n return { layers, rotationBadge, resizeHandles, chromeAffordancesRef, snapStore, departures };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2CA,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,qBAAqB,sBAAsB,KAAK;CACtD,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;CAE3D,MAAM,EAAE,OAAO,UAAU,cAAc,KAAK,oBAAoB,CAAC;CACjE,MAAM,mBAAmB,cAAc,uBAAuB,WAAW;EACvE,GAAI,UAAU,SAAY,EAAE,MAAM,IAAI,CAAC;EACvC,GAAI,aAAa,SAAY,EAAE,SAAS,IAAI,CAAC;EAC7C,GAAI,cAAc,SAAY,EAAE,UAAU,IAAI,CAAC;CACjD,CAAC,GAAG;EAAC;EAAW;EAAO;EAAU;CAAS,CAAC;CAC3C,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,sBAAsB,iBAAiB,KAAK,IAAI,QACrD,aACF;CAEA,MAAM,oBAAoB,0BAA0B,KAAK,cAAc,KAAK,UAAU,KAAK,UAAU;CAkBrG,OAAO;EAAE,QAjBM,eAA6B;GAC1C,GAAG,cAAc,MAAM;GACvB,OAAO;GACP,kBAAkB,wBAAwB,EAAE,OAAO,sBAAsB,IAAI;GAC7E,mBAAmB;IAAE,OAAO;IAAmB,QAAQ;GAAmB;GAC1E,gBAAgB;IAAE,OAAO;IAAgB,OAAO;GAAQ;GACxD,cAAc;IAAE,OAAO;IAAc,OAAO;GAAiB;GAC7D,eAAe;IAAE,OAAO;IAAoB,OAAO;GAAe;GAClE,mBAAmB;IAAE,OAAO;IAAmB,OAAO;GAAgB;GACtE,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;GAAC;GAAQ;GAAa;GAAuB;GAAmB;GAAgB;GAAc;GAAoB;GAAmB;GAAyB;GAAa;GAAe;GAAkB,KAAK;GAAa;GAAO;EACzO,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 'domains/paths/pathEditState';\nimport { usePathEditOverlayLayer } from 'domains/paths/usePathEdit';\nimport type { rotationBadgeOf } from 'domains/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 { layersOverPresets, mergeLayersWithDefaults } from './mergeLayers';\nimport type { SceneCanvasLayers } from './props';\nimport type { EnabledPresets } from './features';\nimport { useDispatcherOverlayLayer } from './useDispatcherOverlayLayer';\nimport { usePreviewGhostLayer } from './usePreviewGhostLayer';\nimport { useDepartureGhostLayer } from './useDepartureGhostLayer';\nimport { useEffectSourcesLayer } from 'domains/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 { useEnteredGroupFrameLayer } from 'domains/selection/enteredGroupFrame';\nimport type { EnteredGroupApi } from '../deps/enteredGroup';\nimport { createSnapOutcomeStore, type SnapOutcomeStore } from 'domains/snap/outcomeStore';\nimport { createSnapReadoutLayer } from 'domains/snap/readoutLayer';\nimport type { SnapReadoutStyle } from 'domains/snap/types';\n\ninterface SceneCanvasLayersArgs<TData, TLayer extends string, TPose> {\n /** `<SceneCanvas layers>`. Omitted, the result is the full default set. */\n layers: SceneCanvasLayers<Node<TData, TLayer, TPose>, TPose> | undefined;\n /** The enabled presets' layers, beneath `layers`: a slot both name is `layers`'. */\n presetLayers: EnabledPresets['layers'];\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; enteredGroup: EnteredGroupApi; frameColor: { read: () => string; changed: (fn: () => void) => () => void };\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\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>(\n args: SceneCanvasLayersArgs<TData, TLayer, TPose>,\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(layersOverPresets(args.presetLayers, args.layers), targetScale, baseSizes),\n [args.layers, args.presetLayers, 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 enteredFrameLayer = useEnteredGroupFrameLayer(args.enteredGroup, args.boundsOf, args.frameColor, scene as never);\n const layers = useMemo<CanvasLayers>(() => ({\n ...builtLayersOf(merged),\n scene: sceneLayers,\n selectionOverlay: selectionOverlayLayer ? { layer: selectionOverlayLayer } : null,\n enteredGroupFrame: { layer: enteredFrameLayer, before: 'selectionOverlay' },\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 }), [merged, sceneLayers, selectionOverlayLayer, enteredFrameLayer, departureLayer, previewLayer, effectSourcesLayer, dispatcherOverlay, pathEditingOverlayLayer, overlaySlot, overlayAnchor, snapReadoutLayer, args.snapReadout, slops, slopsLayer,\n ]);\n\n return { layers, rotationBadge, resizeHandles, chromeAffordancesRef, snapStore, departures };\n}\n"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
- import { isSelectedNode } from "../../features/paths/pathEditState.js";
2
- import { usePathEditState } from "../../features/paths/usePathEdit.js";
1
+ import { isSelectedNode } from "../../domains/paths/pathEditState.js";
2
+ import { usePathEditState } from "../../domains/paths/usePathEdit.js";
3
3
  import { useMemo } from "react";
4
4
 
5
5
  //#region src/canvas/SceneCanvas/useSceneCanvasPathEdit.ts
@@ -1 +1 @@
1
- {"version":3,"file":"useSceneCanvasPathEdit.js","names":[],"sources":["../../../src/canvas/SceneCanvas/useSceneCanvasPathEdit.ts"],"sourcesContent":["import type { ActiveMode } from '@weasel-js/modes';\nimport { useMemo } from 'react';\nimport type { Scene } from 'core/scene/types';\nimport type { SelectionApi } from 'core/selection/useSelection';\nimport { isSelectedNode } from 'features/paths/pathEditState';\nimport { usePathEditState, type UsePathEditStateOptions } from 'features/paths/usePathEdit';\nimport type { SceneCanvasProps } from './props';\n\n/**\n * The canvas's path-edit state, and the select tool options that defer shift-click to it while\n * a path is being anchor-edited.\n */\nexport function useSceneCanvasPathEdit<TData, TLayer extends string, TPose>(args: {\n host: UsePathEditStateOptions['host'];\n opening: UsePathEditStateOptions['opening'];\n getActiveMode: (() => ActiveMode) | undefined;\n scene: Scene<TData, TLayer, TPose>;\n selection: SelectionApi;\n extensions: UsePathEditStateOptions['extensions'];\n selectTool: SceneCanvasProps<TData, TLayer, TPose>['selectTool'];\n}) {\n const { getActiveMode, scene, selection, selectTool } = args;\n // `isAllowed` is absent, not a predicate, when no mode registry is wired: see `PathEditSource.isAllowed`.\n const pathEditState = usePathEditState({\n host: args.host, opening: args.opening,\n isAllowed: getActiveMode\n ? () => getActiveMode().allowedCapabilities.has('edits-anchors')\n : undefined,\n isSelectedNode: (id) => isSelectedNode(scene, selection, id),\n extensions: args.extensions,\n });\n\n const selectToolWithDefaults = useMemo(() => ({\n // Shift-click belongs to the anchor selection while a path is being\n // anchor-edited; see `UseSelectToolOptions.extendClickLocked`.\n extendClickLocked: () => pathEditState.getEditingId() !== '',\n ...selectTool,\n }), [selectTool, pathEditState]);\n\n return { pathEditState, selectToolWithDefaults };\n}\n"],"mappings":";;;;;;;;;AAYA,SAAgB,uBAA4D,MAQzE;CACD,MAAM,EAAE,eAAe,OAAO,WAAW,eAAe;CAExD,MAAM,gBAAgB,iBAAiB;EACrC,MAAM,KAAK;EAAM,SAAS,KAAK;EAC/B,WAAW,sBACD,cAAc,CAAC,CAAC,oBAAoB,IAAI,eAAe,IAC7D;EACJ,iBAAiB,OAAO,eAAe,OAAO,WAAW,EAAE;EAC3D,YAAY,KAAK;CACnB,CAAC;CASD,OAAO;EAAE;EAAe,wBAPO,eAAe;GAG5C,yBAAyB,cAAc,aAAa,MAAM;GAC1D,GAAG;EACL,IAAI,CAAC,YAAY,aAAa,CAEN;CAAuB;AACjD"}
1
+ {"version":3,"file":"useSceneCanvasPathEdit.js","names":[],"sources":["../../../src/canvas/SceneCanvas/useSceneCanvasPathEdit.ts"],"sourcesContent":["import type { ActiveMode } from '@weasel-js/modes';\nimport { useMemo } from 'react';\nimport type { Scene } from 'core/scene/types';\nimport type { SelectionApi } from 'core/selection/useSelection';\nimport { isSelectedNode } from 'domains/paths/pathEditState';\nimport { usePathEditState, type UsePathEditStateOptions } from 'domains/paths/usePathEdit';\nimport type { SceneCanvasProps } from './props';\n\n/**\n * The canvas's path-edit state, and the select tool options that defer shift-click to it while\n * a path is being anchor-edited.\n */\nexport function useSceneCanvasPathEdit<TData, TLayer extends string, TPose>(args: {\n host: UsePathEditStateOptions['host'];\n opening: UsePathEditStateOptions['opening'];\n getActiveMode: (() => ActiveMode) | undefined;\n scene: Scene<TData, TLayer, TPose>;\n selection: SelectionApi;\n extensions: UsePathEditStateOptions['extensions'];\n selectTool: SceneCanvasProps<TData, TLayer, TPose>['selectTool'];\n}) {\n const { getActiveMode, scene, selection, selectTool } = args;\n // `isAllowed` is absent, not a predicate, when no mode registry is wired: see `PathEditSource.isAllowed`.\n const pathEditState = usePathEditState({\n host: args.host, opening: args.opening,\n isAllowed: getActiveMode\n ? () => getActiveMode().allowedCapabilities.has('edits-anchors')\n : undefined,\n isSelectedNode: (id) => isSelectedNode(scene, selection, id),\n extensions: args.extensions,\n });\n\n const selectToolWithDefaults = useMemo(() => ({\n // Shift-click belongs to the anchor selection while a path is being\n // anchor-edited; see `UseSelectToolOptions.extendClickLocked`.\n extendClickLocked: () => pathEditState.getEditingId() !== '',\n ...selectTool,\n }), [selectTool, pathEditState]);\n\n return { pathEditState, selectToolWithDefaults };\n}\n"],"mappings":";;;;;;;;;AAYA,SAAgB,uBAA4D,MAQzE;CACD,MAAM,EAAE,eAAe,OAAO,WAAW,eAAe;CAExD,MAAM,gBAAgB,iBAAiB;EACrC,MAAM,KAAK;EAAM,SAAS,KAAK;EAC/B,WAAW,sBACD,cAAc,CAAC,CAAC,oBAAoB,IAAI,eAAe,IAC7D;EACJ,iBAAiB,OAAO,eAAe,OAAO,WAAW,EAAE;EAC3D,YAAY,KAAK;CACnB,CAAC;CASD,OAAO;EAAE;EAAe,wBAPO,eAAe;GAG5C,yBAAyB,cAAc,aAAa,MAAM;GAC1D,GAAG;EACL,IAAI,CAAC,YAAY,aAAa,CAEN;CAAuB;AACjD"}
@@ -4,7 +4,7 @@ import { useCanvasTools, useFeatureBindings } from "./useCanvasTools.js";
4
4
  /** The canvas's tools, and the contributions and standard actions its presets bring. */
5
5
  function useSceneCanvasTools(args) {
6
6
  const { props, select, enabled } = args;
7
- const { tools, internal, takeover } = useCanvasTools({
7
+ const { tools, internal, takeover, surface } = useCanvasTools({
8
8
  select,
9
9
  groupEntry: enabled.has("select") ? args.groupEntry : null,
10
10
  enabled,
@@ -22,7 +22,9 @@ function useSceneCanvasTools(args) {
22
22
  const { contributions, standardActions } = useFeatureBindings({
23
23
  enabled,
24
24
  pool: args.presetSource.pool,
25
+ baseline: args.presetSource.baseline,
25
26
  tools,
27
+ surface,
26
28
  move: args.move,
27
29
  rotate: props.selectTool?.rotate || void 0
28
30
  });
@@ -30,6 +32,7 @@ function useSceneCanvasTools(args) {
30
32
  tools,
31
33
  internal,
32
34
  takeover,
35
+ surface,
33
36
  contributions,
34
37
  standardActions
35
38
  };
@@ -1 +1 @@
1
- {"version":3,"file":"useSceneCanvasTools.js","names":[],"sources":["../../../src/canvas/SceneCanvas/useSceneCanvasTools.ts"],"sourcesContent":["import type { Contribution, 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 /** Entering and leaving groups, installed with the `select` preset. */\n groupEntry: Contribution;\n}) {\n const { props, select, enabled } = args;\n const { tools, internal, takeover } = useCanvasTools({\n select,\n groupEntry: enabled.has('select') ? args.groupEntry : null,\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,MASjC;CACD,MAAM,EAAE,OAAO,QAAQ,YAAY;CACnC,MAAM,EAAE,OAAO,UAAU,aAAa,eAAe;EACnD;EACA,YAAY,QAAQ,IAAI,QAAQ,IAAI,KAAK,aAAa;EACtD;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"}
1
+ {"version":3,"file":"useSceneCanvasTools.js","names":[],"sources":["../../../src/canvas/SceneCanvas/useSceneCanvasTools.ts"],"sourcesContent":["import type { Contribution, 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 /** Entering and leaving groups, installed with the `select` preset. */\n groupEntry: Contribution;\n}) {\n const { props, select, enabled } = args;\n const { tools, internal, takeover, surface } = useCanvasTools({\n select,\n groupEntry: enabled.has('select') ? args.groupEntry : null,\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, baseline: args.presetSource.baseline,\n tools,\n surface,\n move: args.move as FeatureBindingOptions['move'],\n rotate: (props.selectTool?.rotate || undefined) as FeatureBindingOptions['rotate'],\n });\n return { tools, internal, takeover, surface, contributions, standardActions };\n}\n"],"mappings":";;;;AAeA,SAAgB,oBAAoB,MASjC;CACD,MAAM,EAAE,OAAO,QAAQ,YAAY;CACnC,MAAM,EAAE,OAAO,UAAU,UAAU,YAAY,eAAe;EAC5D;EACA,YAAY,QAAQ,IAAI,QAAQ,IAAI,KAAK,aAAa;EACtD;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;EAAM,UAAU,KAAK,aAAa;EACnE;EACA;EACA,MAAM,KAAK;EACX,QAAS,MAAM,YAAY,UAAU;CACvC,CAAC;CACD,OAAO;EAAE;EAAO;EAAU;EAAU;EAAS;EAAe;CAAgB;AAC9E"}
@@ -1,10 +1,10 @@
1
1
  import { useOptionalViewRegistry } from "../viewRegistry.js";
2
2
  import { worldPointAt } from "./worldPointAt.js";
3
3
  import { PRESET_OWNED_CHROME } from "./presets/chrome.js";
4
- import { never } from "../../features/chrome-caps/conditions.js";
4
+ import { never } from "../../domains/chrome-caps/conditions.js";
5
5
  import { presetChromeRules } from "./features.js";
6
- import { useHoverTracking } from "../../features/chrome-caps/useHoverTracking.js";
7
- import { useChromeCaps } from "../../features/chrome-caps/useChromeCaps.js";
6
+ import { useHoverTracking } from "../../domains/chrome-caps/useHoverTracking.js";
7
+ import { useChromeCaps } from "../../domains/chrome-caps/useChromeCaps.js";
8
8
  import { useCallback, useMemo } from "react";
9
9
  import { useLatest } from "@weasel-js/react";
10
10
 
@@ -26,7 +26,10 @@ function useSceneHover(args) {
26
26
  const view = target?.view ?? viewRef.current;
27
27
  const [x, y] = worldPointAt(api, target, clientX, clientY);
28
28
  const reg = target?.id != null ? surfaceViewRegistry?.list().find((r) => r.id === target.id) : void 0;
29
- const hit = nodeAtPointRef.current?.(x, y, reg ? {
29
+ const hit = nodeAtPointRef.current?.({
30
+ x,
31
+ y
32
+ }, reg ? {
30
33
  scale: view.scale,
31
34
  layerIsPainted: reg.layerIsPainted
32
35
  } : view);
@@ -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 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
+ {"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 'domains/chrome-caps';\nimport {\n useChromeCaps,\n type ChromeCaps,\n type ChromeCapsSource,\n type ViewRuleInputs,\n} from 'domains/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;IAAE;IAAG;GAAE,GAAG,MAAM;IAAE,OAAO,KAAK;IAAO,gBAAgB,IAAI;GAAe,IAAI,IAC9E;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"}
@@ -3,7 +3,7 @@ import { anchorStateFrom, buildAffordanceAt, buildClassifyTarget, layerAffordanc
3
3
  import { useOptionalViewRegistry } from "../viewRegistry.js";
4
4
  import { useDispatchDepSources } from "../deps/dispatchSources.js";
5
5
  import { pathFromPlane } from "../planeClips.js";
6
- import { VIEW_MARKER_ENTRY_ID } from "../../features/viewports/viewMarkerDrag.js";
6
+ import { VIEW_MARKER_ENTRY_ID } from "../../domains/viewports/viewMarkerDrag.js";
7
7
  import { useKitSettingsDepSource } from "../deps/kitSettings.js";
8
8
  import { useChromeAffordances } from "./useChromeAffordances.js";
9
9
  import { useSurfaceRouting } from "./useSurfaceRouting.js";
@@ -68,10 +68,10 @@ function useAffordanceAt(inputs, depRegistry, viewRegistry) {
68
68
  viewRegistry
69
69
  ]);
70
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);
71
+ /** Markers take presses only while the surface binds the marker drag, in the
72
+ * routed tools or beside a takeover: `actions={null}` leaves it out. */
73
+ function useMarkerGate(viewRegistry, ambient, contributions) {
74
+ const installed = [...ambient, ...contributions].some((entry) => entry.id === VIEW_MARKER_ENTRY_ID);
75
75
  const installedRef = useLatest(installed);
76
76
  useEffect(() => viewRegistry?.gateMarkers(() => installedRef.current), [viewRegistry, installedRef]);
77
77
  }
@@ -83,9 +83,9 @@ function useClassifyTarget(inputs, kindOfNodeRef) {
83
83
  const doubleClickNamesRef = useLatest(inputs.doubleClickNames);
84
84
  return useMemo(() => {
85
85
  if (!selectionRef || !pickEvery || !viewRef) return void 0;
86
- return buildClassifyTarget(() => selectionRef.current?.current ?? [], (wx, wy) => {
87
- if (pickBestRef.current) return pickBestRef.current(wx, wy);
88
- const ids = pickEveryRef.current?.(wx, wy) ?? [];
86
+ return buildClassifyTarget(() => selectionRef.current?.current ?? [], (world) => {
87
+ if (pickBestRef.current) return pickBestRef.current(world);
88
+ const ids = pickEveryRef.current?.(world) ?? [];
89
89
  return ids.length > 0 ? ids[ids.length - 1] : null;
90
90
  }, (id) => kindOfNodeRef.current?.(id), (id) => doubleClickNamesRef.current?.(id) ?? id);
91
91
  }, [
@@ -116,7 +116,7 @@ function useSceneGestureDispatcher(inputs) {
116
116
  contributions
117
117
  ]);
118
118
  const kindOfNodeRef = useLatest(kindOfNode);
119
- useMarkerGate(viewRegistry, tools.ambient);
119
+ useMarkerGate(viewRegistry, tools.ambient, contributions);
120
120
  const affordanceWithLayers = useAffordanceAt(inputs, depRegistry, viewRegistry);
121
121
  const classifyTarget = useClassifyTarget(inputs, kindOfNodeRef);
122
122
  const clientToWorld = useCallback((clientX, clientY) => {
@@ -1 +1 @@
1
- {"version":3,"file":"useSceneGestureDispatcher.js","names":[],"sources":["../../../src/canvas/SceneCanvas/useSceneGestureDispatcher.ts"],"sourcesContent":["import { useLatest } from '@weasel-js/react';\nimport { createLongPressStore, type Dispatcher, type DispatchTrace, type TraceRing } from '@weasel-js/routing';\nimport { useActionsRegistry, useDepRegistry, useGestureDispatcher, type DepRegistry } from '@weasel-js/routing/react';\nimport type { Affordance } from 'affordances/types';\nimport { EMPTY_CHROME_STATE } from 'core/selection/chromeState';\nimport type { View } from 'core/viewport/view';\nimport type { RuleCtx } from 'features/chrome-caps';\nimport type React from 'react';\nimport { useCallback, useEffect, useInsertionEffect, useMemo, useState } from 'react';\nimport type { Contribution } from '../../tools/overlayBinding';\nimport type { ToolsApi } from '../../tools/overlayBinding';\nimport { useDispatchDepSources } from '../deps/dispatchSources';\nimport { anchorStateFrom, buildAffordanceAt, buildClassifyTarget, layerAffordance } from '../affordanceAt';\nimport { useChromeAffordances } from './useChromeAffordances';\nimport type { CanvasExtensionApi } from '../canvasExtension';\nimport { useKitSettingsDepSource } from '../deps/kitSettings';\nimport { pathFromPlane } from '../planeClips';\nimport { useOptionalViewRegistry, type ViewRegistry } from '../viewRegistry';\nimport { useSurfaceRouting } from './useSurfaceRouting';\nimport { traceConversion, type CoordTraceEntry } from './coordTrace';\nimport type { SceneCanvasLongPress } from './props';\nimport { VIEW_MARKER_ENTRY_ID } from '../../features/viewports/viewMarkerDrag';\n\n/** What `<SceneCanvas>` hands {@link useSceneGestureDispatcher}. */\nexport interface SceneGestureDispatcherInputs {\n canvasRef: React.RefObject<HTMLElement | null>;\n /** Holds the full `CanvasExtensionApi` so the gesture dispatcher can call\n * `requestRedraw()` between pointer events. */\n canvasApiRef: React.RefObject<CanvasExtensionApi | null>;\n tools: ToolsApi;\n /** Always-live entries the canvas installs beside `tools` — the selection's\n * `move` / `transform` bindings. Ahead of the tools' ambient entries, so a\n * tie at one specificity goes to the kit's. */\n contributions: readonly Contribution[];\n enabled: boolean;\n /** When false, the dispatcher leaves keyboard listeners unattached so\n * keyboard-bound actions never fire. Wired to `enableKeybindings`. */\n keyboard: boolean;\n /** Take the keyboard on mount. Wired to `claimKeys`. */\n claimKeys: boolean;\n selectionRef?: React.RefObject<import('core/selection/useSelection').SelectionApi>;\n boundsOf?: (id: string) => import('core/viewport/fitViewToBounds').Bounds | null;\n /** The parallax plane a node is drawn through, under the surface's camera —\n * so path anchors are hit where the plane draws them. */\n planeOfNode?: (id: string) => import('core/viewport/parallax').PlaneMap | null;\n pickEvery?: (worldX: number, worldY: number) => string[];\n /** Single topmost hit (collapses parent/child via `pickTopMostHit`), used to\n * classify the body under the pointer. Must match the select tool's own\n * resolution so a child node isn't misclassified by its parent's selection.\n * Falls back to `pickEvery`'s last id when absent. */\n pickBest?: (worldX: number, worldY: number) => string | null;\n /** Resolves a hit node id to its routing-trait kind, so the body\n * classification carries `kind` alongside `bodyTarget` and the\n * `kind:<k>` / `kind:<k>:selected` target forms can match. Absent when\n * the consumer opted out of routing (`routing={[]}`). */\n kindOfNode?: (id: string) => string | undefined;\n /** The node a double-click on a hit names (`doubleClickTarget`), for the classification. */\n doubleClickNames?: (hitId: string) => string;\n viewRef?: React.RefObject<View>;\n /** Pre-created dispatcher to pump events into. When omitted,\n * `useGestureDispatcher` creates one internally (legacy path). */\n dispatcher?: Dispatcher;\n /** Where the dispatcher records its decisions and `clientToWorld` its conversions. */\n traces: { dispatch: DispatchTrace; coords: TraceRing<CoordTraceEntry> };\n /** Chrome-caps visibility resolver factory. Threaded into\n * `buildAffordanceAt` so the hit-test pipeline gates corner / rotate /\n * anchor affordances on the same chrome ids the renderer uses. */\n getIsVisibleForCanvas?: () => (id: string) => boolean;\n /** Live RuleCtx factory. Threaded into `useGestureDispatcher` so the\n * dispatcher's eligibility filter sees the same mode/capabilities/selection\n * view of the world that chrome-caps does. */\n getRuleCtx?: () => RuleCtx | undefined;\n /** `DeviceProfile.targetScale`, so the affordance grab zones resolve to the\n * same sizes the chrome paints at. */\n targetScale?: number;\n /** Consumer override for the corner-handle grab radius\n * (`selectTool.handleHitRadius`). Undefined takes the device-scaled size. */\n handleHitRadius?: number;\n /** `selectTool.resize.edgeHandles`: resize handles at the edge midpoints. Default true. */\n edgeHandles?: boolean;\n /** The rotate badge the selection overlay paints, grabbable where drawn. */\n rotationBadge?: { distancePx: number; sizePx: number } | null;\n /** Receives the affordances this mounter hit-tests, for the slops overlay. */\n chromeAffordancesRef?: React.MutableRefObject<readonly Affordance[]>;\n /** Fires on every synthesized double click, in world coords. Backs the\n * `onDoubleClick` prop — see the option's doc on\n * `UseGestureDispatcherOptions` for why it's an observer, not a binding. */\n onDoubleClick?: (world: { x: number; y: number }) => void;\n /** Fires after every synthesized click. Backs the `onClick` prop. */\n onClick?: (world: { x: number; y: number }) => void;\n /** Backs `<SceneCanvas longPress>`. */\n longPress?: SceneCanvasLongPress;\n}\n\ntype AffordanceInputs = Pick<\n SceneGestureDispatcherInputs,\n | 'canvasApiRef' | 'selectionRef' | 'boundsOf' | 'planeOfNode' | 'viewRef' | 'getIsVisibleForCanvas'\n | 'targetScale' | 'handleHitRadius' | 'edgeHandles' | 'rotationBadge' | 'chromeAffordancesRef'\n>;\n\n/** What a press on the canvas grabs: a registered layer's widget, else a piece of the\n * selection chrome. */\nfunction useAffordanceAt(inputs: AffordanceInputs, depRegistry: DepRegistry, viewRegistry: ViewRegistry | null) {\n const {\n canvasApiRef, selectionRef, boundsOf, planeOfNode, viewRef, getIsVisibleForCanvas,\n targetScale, handleHitRadius, edgeHandles, rotationBadge, chromeAffordancesRef,\n } = inputs;\n // `getAnchorState` thunk for `buildAffordanceAt` — reads the live\n // `editAnchors` dep from the registry at call time.\n const depRegistryRef = useLatest(depRegistry);\n const planeOfNodeRef = useLatest(planeOfNode);\n const getAnchorState = useMemo(() => anchorStateFrom(\n () => depRegistryRef.current,\n (id, path) => pathFromPlane(path, planeOfNodeRef.current?.(id) ?? null),\n ), [depRegistryRef, planeOfNodeRef]);\n\n // Build the `affordanceAt` thunk. Takes world coords and delegates to\n // `buildAffordanceAt` for handle hit-testing.\n const affordances = useChromeAffordances({ targetScale, handleHitRadius, edgeHandles, rotationBadge, getAnchorState });\n useInsertionEffect(() => {\n if (chromeAffordancesRef) chromeAffordancesRef.current = affordances;\n });\n const affordanceAt = useMemo(() => {\n if (!selectionRef || !boundsOf || !viewRef) return undefined;\n return buildAffordanceAt({\n // The canvas's own view chrome, built once by its helpers — not a\n // second construction here that has to agree with the painted one.\n getChromeState: () => viewRegistry?.surface()?.chromeState() ?? EMPTY_CHROME_STATE,\n // Radii are declared in screen pixels and converted against this view.\n getView: () => viewRef.current ?? { x: 0, y: 0, scale: { x: 1, y: 1 } },\n affordances,\n // Chrome-caps resolver: keep the affordance hit-test in sync with what\n // the renderer is actually painting. Without this, a click on a (no\n // longer visible) resize handle position still classifies as a resize\n // handle — e.g. an anchor drag in path-edit mode resizes the path's\n // bounding box instead of moving the anchor.\n ...(getIsVisibleForCanvas ? { getIsVisible: () => getIsVisibleForCanvas() } : {}),\n });\n }, [selectionRef, boundsOf, viewRef, affordances, getIsVisibleForCanvas, viewRegistry]);\n\n return useMemo(() => {\n // Note this is NOT gated on `affordanceAt` being built: registered layers\n // produce affordances of their own, and a consumer with no selection\n // chrome (a canvas that is nothing but a HUD, say) still needs those.\n return (worldPoint: { x: number; y: number }) => {\n // Registered layers first: they draw on top of the kit's own chrome, so\n // they get first refusal on the point. A hit becomes an `AffordanceHit`\n // whose kind names the layer, carrying whatever the layer's hit-test\n // resolved — which is how `@weasel-js/hud` routes a press on one of its\n // widgets to its own action instead of the active tool.\n const extra = canvasApiRef.current?.hitTestExtras?.(worldPoint.x, worldPoint.y);\n if (extra) return layerAffordance(extra.layerId, extra.hit);\n const marker = viewRegistry?.markerAt(null, worldPoint);\n if (marker) return marker;\n return affordanceAt ? affordanceAt(worldPoint) : null;\n };\n }, [affordanceAt, canvasApiRef, viewRegistry]);\n}\n\n/** Markers take presses only while the routed tools carry the marker drag:\n * `actions={null}` and a tools takeover both leave it out. */\nfunction useMarkerGate(viewRegistry: ViewRegistry | null, ambient: readonly Contribution[]): void {\n const installed = ambient.some((entry) => entry.id === VIEW_MARKER_ENTRY_ID);\n const installedRef = useLatest(installed);\n useEffect(() => viewRegistry?.gateMarkers(() => installedRef.current), [viewRegistry, installedRef]);\n}\n\n/** Which body a world point lands on, its selection state, and its routing kind. */\nfunction useClassifyTarget(\n inputs: Pick<SceneGestureDispatcherInputs, 'selectionRef' | 'pickEvery' | 'pickBest' | 'viewRef' | 'doubleClickNames'>,\n kindOfNodeRef: { readonly current: SceneGestureDispatcherInputs['kindOfNode'] },\n) {\n const { selectionRef, pickEvery, pickBest, viewRef } = inputs;\n // Stable refs for the optional thunk inputs so the thunks themselves are\n // stable function identities across renders (no need to pass them as deps).\n const pickEveryRef = useLatest(pickEvery);\n const pickBestRef = useLatest(pickBest);\n const doubleClickNamesRef = useLatest(inputs.doubleClickNames);\n // Build the `classifyTarget` thunk. Takes world coords and delegates to\n // `buildClassifyTarget`.\n return useMemo(() => {\n if (!selectionRef || !pickEvery || !viewRef) return undefined;\n return buildClassifyTarget(\n () => selectionRef.current?.current ?? [],\n // Use the select tool's own topmost-hit resolution (`pickTopMostHit`,\n // which collapses parent/child) so a child body is classified by ITS\n // OWN selection — not its parent's.\n (wx: number, wy: number) => {\n if (pickBestRef.current) return pickBestRef.current(wx, wy);\n const ids = pickEveryRef.current?.(wx, wy) ?? [];\n return ids.length > 0 ? ids[ids.length - 1] : null;\n },\n // Node kind comes from the routing trait — the same classifier that\n // names `Hit.kind` — so `target: 'kind:text'` on a binding speaks the\n // vocabulary the consumer already declared in `routing`, rather than a\n // second one invented for bindings. `routing={[]}` opts out and leaves\n // every `kind:` target unmatchable.\n (id: string) => kindOfNodeRef.current?.(id),\n (id: string) => doubleClickNamesRef.current?.(id) ?? id,\n );\n }, [selectionRef, pickEvery, viewRef, pickBestRef, pickEveryRef, kindOfNodeRef, doubleClickNamesRef]);\n}\n\n/** Runs this canvas's gesture dispatcher over its tools, contributions, and chrome. */\nexport function useSceneGestureDispatcher(inputs: SceneGestureDispatcherInputs): void {\n const {\n canvasRef, canvasApiRef, tools, contributions, enabled, keyboard, claimKeys, viewRef,\n kindOfNode, dispatcher, traces, getRuleCtx, onDoubleClick, onClick,\n longPress: { duration: longPressDuration, haptics: longPressHaptics } = {},\n } = inputs;\n const registry = useActionsRegistry();\n const depRegistry = useDepRegistry();\n const viewRegistry = useOptionalViewRegistry();\n const entriesById = useMemo<ReadonlyMap<string, Contribution>>(() => {\n const m = new Map<string, Contribution>();\n for (const [id, tool] of Object.entries(tools.registry)) {\n m.set(id, tool);\n }\n for (const entry of contributions) m.set(entry.id, entry);\n // Ambient entries too — their bindings assemble at ambient scope, and the\n // dispatcher resolves them through this same map.\n for (const entry of tools.ambient) m.set(entry.id, entry);\n return m;\n }, [tools.registry, tools.ambient, contributions]);\n\n const kindOfNodeRef = useLatest(kindOfNode);\n useMarkerGate(viewRegistry, tools.ambient);\n\n const affordanceWithLayers = useAffordanceAt(inputs, depRegistry, viewRegistry);\n const classifyTarget = useClassifyTarget(inputs, kindOfNodeRef);\n\n // Through the handle, so a `clientToWorld` override on the canvas applies.\n const clientToWorld = useCallback((clientX: number, clientY: number): { x: number; y: number } => {\n const api = canvasApiRef.current;\n const [x, y] = api ? api.clientToWorld(clientX, clientY) : [clientX, clientY];\n const world = { x, y };\n traceConversion(traces.coords, clientX, clientY, api ? canvasRef.current : null, viewRef?.current, world);\n return world;\n }, [canvasRef, canvasApiRef, viewRef, traces.coords]);\n\n // Stable callback that asks the canvas to redraw. Reads via ref so the\n // identity stays stable while the underlying API binds after mount.\n const requestRedraw = useCallback(() => {\n canvasApiRef.current?.requestRedraw?.();\n }, [canvasApiRef]);\n\n // The painted tier's channel, read live for the same reason — the handle it\n // lives on binds after mount.\n const paintedCursor = useCallback(() => canvasApiRef.current?.paintedCursor, [canvasApiRef]);\n const cursorSink = useCallback(() => canvasApiRef.current?.cursorSink, [canvasApiRef]);\n\n // The pending long-press, published as the `longPress` dep for feedback.\n const [longPressState] = useState(createLongPressStore);\n const longPress = useMemo(() => ({\n state: longPressState,\n ...(longPressDuration !== undefined ? { duration: longPressDuration } : {}),\n ...(longPressHaptics !== undefined ? { haptics: longPressHaptics } : {}),\n }), [longPressState, longPressDuration, longPressHaptics]);\n\n const routing = useSurfaceRouting(viewRegistry);\n\n // Hover cursors live in `useGestureDispatcher`'s hover-cursor pump:\n // affordance hits carry `AffordanceHit.cursor` (set by `buildAffordanceAt`),\n // and everything else is predicted via `Dispatcher.resolveOnly` +\n // `Action.cursor`. Nothing SceneCanvas-specific remains here.\n useGestureDispatcher({\n canvasRef,\n actions: registry!,\n entriesById,\n enabled,\n keyboard,\n claimKeys,\n affordanceAt: affordanceWithLayers,\n classifyTarget,\n dispatcher,\n trace: traces.dispatch,\n clientToWorld,\n requestRedraw,\n paintedCursor,\n cursorSink,\n getRuleCtx,\n onClick,\n onDoubleClick,\n longPress,\n ...routing,\n });\n useDispatchDepSources(longPressState, classifyTarget, kindOfNodeRef);\n useKitSettingsDepSource();\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"useSceneGestureDispatcher.js","names":[],"sources":["../../../src/canvas/SceneCanvas/useSceneGestureDispatcher.ts"],"sourcesContent":["import { useLatest } from '@weasel-js/react';\nimport { createLongPressStore, type Dispatcher, type DispatchTrace, type TraceRing, type WorldPoint } from '@weasel-js/routing';\nimport { useActionsRegistry, useDepRegistry, useGestureDispatcher, type DepRegistry } from '@weasel-js/routing/react';\nimport type { Affordance } from 'affordances/types';\nimport { EMPTY_CHROME_STATE } from 'core/selection/chromeState';\nimport type { View } from 'core/viewport/view';\nimport type { RuleCtx } from 'domains/chrome-caps';\nimport type React from 'react';\nimport { useCallback, useEffect, useInsertionEffect, useMemo, useState } from 'react';\nimport type { Contribution } from '../../tools/overlayBinding';\nimport type { ToolsApi } from '../../tools/overlayBinding';\nimport { useDispatchDepSources } from '../deps/dispatchSources';\nimport { anchorStateFrom, buildAffordanceAt, buildClassifyTarget, layerAffordance } from '../affordanceAt';\nimport { useChromeAffordances } from './useChromeAffordances';\nimport type { CanvasExtensionApi } from '../canvasExtension';\nimport { useKitSettingsDepSource } from '../deps/kitSettings';\nimport { pathFromPlane } from '../planeClips';\nimport { useOptionalViewRegistry, type ViewRegistry } from '../viewRegistry';\nimport { useSurfaceRouting } from './useSurfaceRouting';\nimport { traceConversion, type CoordTraceEntry } from './coordTrace';\nimport type { SceneCanvasLongPress } from './props';\nimport { VIEW_MARKER_ENTRY_ID } from '../../domains/viewports/viewMarkerDrag';\n\n/** What `<SceneCanvas>` hands {@link useSceneGestureDispatcher}. */\nexport interface SceneGestureDispatcherInputs {\n canvasRef: React.RefObject<HTMLElement | null>;\n /** Holds the full `CanvasExtensionApi` so the gesture dispatcher can call\n * `requestRedraw()` between pointer events. */\n canvasApiRef: React.RefObject<CanvasExtensionApi | null>;\n tools: ToolsApi;\n /** Always-live entries the canvas installs beside `tools` — the selection's\n * `move` / `transform` bindings. Ahead of the tools' ambient entries, so a\n * tie at one specificity goes to the kit's. */\n contributions: readonly Contribution[];\n enabled: boolean;\n /** When false, the dispatcher leaves keyboard listeners unattached so\n * keyboard-bound actions never fire. Wired to `enableKeybindings`. */\n keyboard: boolean;\n /** Take the keyboard on mount. Wired to `claimKeys`. */\n claimKeys: boolean;\n selectionRef?: React.RefObject<import('core/selection/useSelection').SelectionApi>;\n boundsOf?: (id: string) => import('core/viewport/fitViewToBounds').Bounds | null;\n /** The parallax plane a node is drawn through, under the surface's camera —\n * so path anchors are hit where the plane draws them. */\n planeOfNode?: (id: string) => import('core/viewport/parallax').PlaneMap | null;\n pickEvery?: (world: WorldPoint) => string[];\n /** Single topmost hit (collapses parent/child via `pickTopMostHit`), used to\n * classify the body under the pointer. Must match the select tool's own\n * resolution so a child node isn't misclassified by its parent's selection.\n * Falls back to `pickEvery`'s last id when absent. */\n pickBest?: (world: WorldPoint) => string | null;\n /** Resolves a hit node id to its routing-trait kind, so the body\n * classification carries `kind` alongside `bodyTarget` and the\n * `kind:<k>` / `kind:<k>:selected` target forms can match. Absent when\n * the consumer opted out of routing (`routing={[]}`). */\n kindOfNode?: (id: string) => string | undefined;\n /** The node a double-click on a hit names (`doubleClickTarget`), for the classification. */\n doubleClickNames?: (hitId: string) => string;\n viewRef?: React.RefObject<View>;\n /** Pre-created dispatcher to pump events into. When omitted,\n * `useGestureDispatcher` creates one internally (legacy path). */\n dispatcher?: Dispatcher;\n /** Where the dispatcher records its decisions and `clientToWorld` its conversions. */\n traces: { dispatch: DispatchTrace; coords: TraceRing<CoordTraceEntry> };\n /** Chrome-caps visibility resolver factory. Threaded into\n * `buildAffordanceAt` so the hit-test pipeline gates corner / rotate /\n * anchor affordances on the same chrome ids the renderer uses. */\n getIsVisibleForCanvas?: () => (id: string) => boolean;\n /** Live RuleCtx factory. Threaded into `useGestureDispatcher` so the\n * dispatcher's eligibility filter sees the same mode/capabilities/selection\n * view of the world that chrome-caps does. */\n getRuleCtx?: () => RuleCtx | undefined;\n /** `DeviceProfile.targetScale`, so the affordance grab zones resolve to the\n * same sizes the chrome paints at. */\n targetScale?: number;\n /** Consumer override for the corner-handle grab radius\n * (`selectTool.handleHitRadius`). Undefined takes the device-scaled size. */\n handleHitRadius?: number;\n /** `selectTool.resize.edgeHandles`: resize handles at the edge midpoints. Default true. */\n edgeHandles?: boolean;\n /** The rotate badge the selection overlay paints, grabbable where drawn. */\n rotationBadge?: { distancePx: number; sizePx: number } | null;\n /** Receives the affordances this mounter hit-tests, for the slops overlay. */\n chromeAffordancesRef?: React.MutableRefObject<readonly Affordance[]>;\n /** Fires on every synthesized double click, in world coords. Backs the\n * `onDoubleClick` prop — see the option's doc on\n * `UseGestureDispatcherOptions` for why it's an observer, not a binding. */\n onDoubleClick?: (world: { x: number; y: number }) => void;\n /** Fires after every synthesized click. Backs the `onClick` prop. */\n onClick?: (world: { x: number; y: number }) => void;\n /** Backs `<SceneCanvas longPress>`. */\n longPress?: SceneCanvasLongPress;\n}\n\ntype AffordanceInputs = Pick<\n SceneGestureDispatcherInputs,\n | 'canvasApiRef' | 'selectionRef' | 'boundsOf' | 'planeOfNode' | 'viewRef' | 'getIsVisibleForCanvas'\n | 'targetScale' | 'handleHitRadius' | 'edgeHandles' | 'rotationBadge' | 'chromeAffordancesRef'\n>;\n\n/** What a press on the canvas grabs: a registered layer's widget, else a piece of the\n * selection chrome. */\nfunction useAffordanceAt(inputs: AffordanceInputs, depRegistry: DepRegistry, viewRegistry: ViewRegistry | null) {\n const {\n canvasApiRef, selectionRef, boundsOf, planeOfNode, viewRef, getIsVisibleForCanvas,\n targetScale, handleHitRadius, edgeHandles, rotationBadge, chromeAffordancesRef,\n } = inputs;\n // `getAnchorState` thunk for `buildAffordanceAt` — reads the live\n // `editAnchors` dep from the registry at call time.\n const depRegistryRef = useLatest(depRegistry);\n const planeOfNodeRef = useLatest(planeOfNode);\n const getAnchorState = useMemo(() => anchorStateFrom(\n () => depRegistryRef.current,\n (id, path) => pathFromPlane(path, planeOfNodeRef.current?.(id) ?? null),\n ), [depRegistryRef, planeOfNodeRef]);\n\n // Build the `affordanceAt` thunk. Takes world coords and delegates to\n // `buildAffordanceAt` for handle hit-testing.\n const affordances = useChromeAffordances({ targetScale, handleHitRadius, edgeHandles, rotationBadge, getAnchorState });\n useInsertionEffect(() => {\n if (chromeAffordancesRef) chromeAffordancesRef.current = affordances;\n });\n const affordanceAt = useMemo(() => {\n if (!selectionRef || !boundsOf || !viewRef) return undefined;\n return buildAffordanceAt({\n // The canvas's own view chrome, built once by its helpers — not a\n // second construction here that has to agree with the painted one.\n getChromeState: () => viewRegistry?.surface()?.chromeState() ?? EMPTY_CHROME_STATE,\n // Radii are declared in screen pixels and converted against this view.\n getView: () => viewRef.current ?? { x: 0, y: 0, scale: { x: 1, y: 1 } },\n affordances,\n // Chrome-caps resolver: keep the affordance hit-test in sync with what\n // the renderer is actually painting. Without this, a click on a (no\n // longer visible) resize handle position still classifies as a resize\n // handle — e.g. an anchor drag in path-edit mode resizes the path's\n // bounding box instead of moving the anchor.\n ...(getIsVisibleForCanvas ? { getIsVisible: () => getIsVisibleForCanvas() } : {}),\n });\n }, [selectionRef, boundsOf, viewRef, affordances, getIsVisibleForCanvas, viewRegistry]);\n\n return useMemo(() => {\n // Note this is NOT gated on `affordanceAt` being built: registered layers\n // produce affordances of their own, and a consumer with no selection\n // chrome (a canvas that is nothing but a HUD, say) still needs those.\n return (worldPoint: { x: number; y: number }) => {\n // Registered layers first: they draw on top of the kit's own chrome, so\n // they get first refusal on the point. A hit becomes an `AffordanceHit`\n // whose kind names the layer, carrying whatever the layer's hit-test\n // resolved — which is how `@weasel-js/hud` routes a press on one of its\n // widgets to its own action instead of the active tool.\n const extra = canvasApiRef.current?.hitTestExtras?.(worldPoint.x, worldPoint.y);\n if (extra) return layerAffordance(extra.layerId, extra.hit);\n const marker = viewRegistry?.markerAt(null, worldPoint);\n if (marker) return marker;\n return affordanceAt ? affordanceAt(worldPoint) : null;\n };\n }, [affordanceAt, canvasApiRef, viewRegistry]);\n}\n\n/** Markers take presses only while the surface binds the marker drag, in the\n * routed tools or beside a takeover: `actions={null}` leaves it out. */\nfunction useMarkerGate(\n viewRegistry: ViewRegistry | null, ambient: readonly Contribution[], contributions: readonly Contribution[],\n): void {\n const installed = [...ambient, ...contributions].some((entry) => entry.id === VIEW_MARKER_ENTRY_ID);\n const installedRef = useLatest(installed);\n useEffect(() => viewRegistry?.gateMarkers(() => installedRef.current), [viewRegistry, installedRef]);\n}\n\n/** Which body a world point lands on, its selection state, and its routing kind. */\nfunction useClassifyTarget(\n inputs: Pick<SceneGestureDispatcherInputs, 'selectionRef' | 'pickEvery' | 'pickBest' | 'viewRef' | 'doubleClickNames'>,\n kindOfNodeRef: { readonly current: SceneGestureDispatcherInputs['kindOfNode'] },\n) {\n const { selectionRef, pickEvery, pickBest, viewRef } = inputs;\n // Stable refs for the optional thunk inputs so the thunks themselves are\n // stable function identities across renders (no need to pass them as deps).\n const pickEveryRef = useLatest(pickEvery);\n const pickBestRef = useLatest(pickBest);\n const doubleClickNamesRef = useLatest(inputs.doubleClickNames);\n // Build the `classifyTarget` thunk. Takes world coords and delegates to\n // `buildClassifyTarget`.\n return useMemo(() => {\n if (!selectionRef || !pickEvery || !viewRef) return undefined;\n return buildClassifyTarget(\n () => selectionRef.current?.current ?? [],\n // Use the select tool's own topmost-hit resolution (`pickTopMostHit`,\n // which collapses parent/child) so a child body is classified by ITS\n // OWN selection — not its parent's.\n (world: WorldPoint) => {\n if (pickBestRef.current) return pickBestRef.current(world);\n const ids = pickEveryRef.current?.(world) ?? [];\n return ids.length > 0 ? ids[ids.length - 1] : null;\n },\n // Node kind comes from the routing trait — the same classifier that\n // names `Hit.kind` — so `target: 'kind:text'` on a binding speaks the\n // vocabulary the consumer already declared in `routing`, rather than a\n // second one invented for bindings. `routing={[]}` opts out and leaves\n // every `kind:` target unmatchable.\n (id: string) => kindOfNodeRef.current?.(id),\n (id: string) => doubleClickNamesRef.current?.(id) ?? id,\n );\n }, [selectionRef, pickEvery, viewRef, pickBestRef, pickEveryRef, kindOfNodeRef, doubleClickNamesRef]);\n}\n\n/** Runs this canvas's gesture dispatcher over its tools, contributions, and chrome. */\nexport function useSceneGestureDispatcher(inputs: SceneGestureDispatcherInputs): void {\n const {\n canvasRef, canvasApiRef, tools, contributions, enabled, keyboard, claimKeys, viewRef,\n kindOfNode, dispatcher, traces, getRuleCtx, onDoubleClick, onClick,\n longPress: { duration: longPressDuration, haptics: longPressHaptics } = {},\n } = inputs;\n const registry = useActionsRegistry();\n const depRegistry = useDepRegistry();\n const viewRegistry = useOptionalViewRegistry();\n const entriesById = useMemo<ReadonlyMap<string, Contribution>>(() => {\n const m = new Map<string, Contribution>();\n for (const [id, tool] of Object.entries(tools.registry)) {\n m.set(id, tool);\n }\n for (const entry of contributions) m.set(entry.id, entry);\n // Ambient entries too — their bindings assemble at ambient scope, and the\n // dispatcher resolves them through this same map.\n for (const entry of tools.ambient) m.set(entry.id, entry);\n return m;\n }, [tools.registry, tools.ambient, contributions]);\n\n const kindOfNodeRef = useLatest(kindOfNode);\n useMarkerGate(viewRegistry, tools.ambient, contributions);\n\n const affordanceWithLayers = useAffordanceAt(inputs, depRegistry, viewRegistry);\n const classifyTarget = useClassifyTarget(inputs, kindOfNodeRef);\n\n // Through the handle, so a `clientToWorld` override on the canvas applies.\n const clientToWorld = useCallback((clientX: number, clientY: number): { x: number; y: number } => {\n const api = canvasApiRef.current;\n const [x, y] = api ? api.clientToWorld(clientX, clientY) : [clientX, clientY];\n const world = { x, y };\n traceConversion(traces.coords, clientX, clientY, api ? canvasRef.current : null, viewRef?.current, world);\n return world;\n }, [canvasRef, canvasApiRef, viewRef, traces.coords]);\n\n // Stable callback that asks the canvas to redraw. Reads via ref so the\n // identity stays stable while the underlying API binds after mount.\n const requestRedraw = useCallback(() => {\n canvasApiRef.current?.requestRedraw?.();\n }, [canvasApiRef]);\n\n // The painted tier's channel, read live for the same reason — the handle it\n // lives on binds after mount.\n const paintedCursor = useCallback(() => canvasApiRef.current?.paintedCursor, [canvasApiRef]);\n const cursorSink = useCallback(() => canvasApiRef.current?.cursorSink, [canvasApiRef]);\n\n // The pending long-press, published as the `longPress` dep for feedback.\n const [longPressState] = useState(createLongPressStore);\n const longPress = useMemo(() => ({\n state: longPressState,\n ...(longPressDuration !== undefined ? { duration: longPressDuration } : {}),\n ...(longPressHaptics !== undefined ? { haptics: longPressHaptics } : {}),\n }), [longPressState, longPressDuration, longPressHaptics]);\n\n const routing = useSurfaceRouting(viewRegistry);\n\n // Hover cursors live in `useGestureDispatcher`'s hover-cursor pump:\n // affordance hits carry `AffordanceHit.cursor` (set by `buildAffordanceAt`),\n // and everything else is predicted via `Dispatcher.resolveOnly` +\n // `Action.cursor`. Nothing SceneCanvas-specific remains here.\n useGestureDispatcher({\n canvasRef,\n actions: registry!,\n entriesById,\n enabled,\n keyboard,\n claimKeys,\n affordanceAt: affordanceWithLayers,\n classifyTarget,\n dispatcher,\n trace: traces.dispatch,\n clientToWorld,\n requestRedraw,\n paintedCursor,\n cursorSink,\n getRuleCtx,\n onClick,\n onDoubleClick,\n longPress,\n ...routing,\n });\n useDispatchDepSources(longPressState, classifyTarget, kindOfNodeRef);\n useKitSettingsDepSource();\n}\n"],"mappings":"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"}
@@ -4,11 +4,11 @@ import { useEnteredGroup } from "../deps/enteredGroup.js";
4
4
  import { useViewLayerGate } from "../useViewLayerGate.js";
5
5
  import { composeAlphaFor } from "../sceneSlotWiring.js";
6
6
  import { doubleClickTarget } from "../doubleClickTarget.js";
7
- import { createEnteredGroupScope } from "../../features/selection/enteredGroupScope.js";
7
+ import { createEnteredGroupScope } from "../../domains/selection/enteredGroupScope.js";
8
8
  import { useSceneAdapter } from "../useSceneAdapter.js";
9
9
  import { useNodeAtPoint } from "./useNodeAtPoint.js";
10
10
  import { useSceneSelectTool } from "./useSceneSelectTool.js";
11
- import { useCallback, useMemo, useSyncExternalStore } from "react";
11
+ import { useCallback, useMemo } from "react";
12
12
  import { useLatest } from "@weasel-js/react";
13
13
  import { useOptionalDepRegistry } from "@weasel-js/routing/react";
14
14
 
@@ -25,16 +25,13 @@ function useScenePicking(args) {
25
25
  const ownEntered = useEnteredGroup(scene);
26
26
  const enteredGroup = args.props.enteredGroup ?? ownEntered;
27
27
  const consumerInteractive = useLatest(isPointerInteractive);
28
- const filtering = useSyncExternalStore(enteredGroup.subscribe, () => enteredGroup.get() !== null) || isPointerInteractive !== void 0;
29
28
  const reachable = useMemo(() => {
30
- if (!filtering) return void 0;
31
29
  const scope = createEnteredGroupScope({
32
30
  entered: enteredGroup,
33
31
  scene
34
32
  });
35
33
  return (id) => scope.isPointerInteractive(id) && consumerInteractive.current?.(id) !== false;
36
34
  }, [
37
- filtering,
38
35
  enteredGroup,
39
36
  scene,
40
37
  consumerInteractive
@@ -56,7 +53,7 @@ function useScenePicking(args) {
56
53
  getView: () => viewRef.current,
57
54
  ...alphaFor ? { alphaOf: composedAlphaFor } : {},
58
55
  ...viewLayerGate ? { layerIsPainted: viewLayerGate } : {},
59
- ...reachable ? { isPointerInteractive: reachable } : {},
56
+ isPointerInteractive: reachable,
60
57
  selectTool: args.selectTool
61
58
  });
62
59
  const getNodeAtPoint = useNodeAtPoint({
@@ -81,7 +78,7 @@ function useScenePicking(args) {
81
78
  getNodeAtPoint,
82
79
  viewLayerGate,
83
80
  enteredGroup,
84
- /** What a press or a region select can reach, or undefined when that is every node. */
81
+ /** What a press or a region select can reach. */
85
82
  reachable,
86
83
  /** The composed paint alpha, only when the consumer fades anything. */
87
84
  alphaOf: alphaFor ? composedAlphaFor : void 0
@@ -1 +1 @@
1
- {"version":3,"file":"useScenePicking.js","names":[],"sources":["../../../src/canvas/SceneCanvas/useScenePicking.ts"],"sourcesContent":["import { useCallback, useMemo, useSyncExternalStore, type RefObject } from 'react';\nimport { useOptionalDepRegistry } from '@weasel-js/routing/react';\nimport { asNodeId, type Scene } from 'core/scene/types';\nimport { useLatest } from '@weasel-js/react';\nimport { doubleClickTarget } from '../doubleClickTarget';\nimport { useEnteredGroup } from '../deps/enteredGroup';\nimport { createEnteredGroupScope } from 'features/selection/enteredGroupScope';\nimport type { SelectionApi } from 'core/selection/useSelection';\nimport type { View } from 'core/viewport/view';\nimport type { PoseDescriptor } from 'interactions/actions/resize/geometry';\nimport { composeAlphaFor } from '../sceneSlotWiring';\nimport { useSceneAdapter } from '../useSceneAdapter';\nimport type { SceneCanvasProps } from './props';\nimport { useNodeAtPoint } from './useNodeAtPoint';\nimport type { NodeKinds } from './useNodeKinds';\nimport { useSceneSelectTool, type UseSceneSelectToolArgs } from './useSceneSelectTool';\nimport { useOptionalViewRegistry } from '../viewRegistry';\nimport { useViewLayerGate } from '../useViewLayerGate';\n\ntype PickingProps<TData, TLayer extends string, TPose> = Pick<\n SceneCanvasProps<TData, TLayer, TPose>,\n 'geometry' | 'alphaFor' | 'layerVisibility' | 'layerOrder' | 'isPointerInteractive' | 'enteredGroup'\n>;\n\n/**\n * The canvas's adapter and everything that answers \"what is under this point\": the select\n * tool's pickers and bounds, the node kinds, and the paint gates picking shares with the painter.\n */\nexport function useScenePicking<TData, TLayer extends string, TPose>(args: {\n scene: Scene<TData, TLayer, TPose>;\n selection: SelectionApi;\n descriptor: PoseDescriptor<TPose>;\n props: PickingProps<TData, TLayer, TPose>;\n viewRef: RefObject<View>;\n selectTool: UseSceneSelectToolArgs<TData, TLayer, TPose>['selectTool'];\n kinds: NodeKinds<TData>;\n}) {\n const { scene, selection, descriptor, viewRef } = args;\n const { geometry, alphaFor, layerVisibility, layerOrder, isPointerInteractive } = args.props;\n const { kindOf, kindOfNode } = args.kinds;\n\n // The painted alpha of a node in this view: the caller's `alphaFor` times any per-node\n // override alpha. The pick path reads the same number the painter does, or a node faded\n // to nothing stays clickable.\n const composedAlphaFor = useMemo(\n () => composeAlphaFor(scene, alphaFor),\n [scene, alphaFor],\n );\n const ownEntered = useEnteredGroup(scene);\n const enteredGroup = args.props.enteredGroup ?? ownEntered;\n // A press resolves inside the entered group, so nothing outside it takes a hit. With nothing\n // entered and no consumer predicate there is nothing to filter, and the walk runs bare.\n const consumerInteractive = useLatest(isPointerInteractive);\n const anyEntered = useSyncExternalStore(enteredGroup.subscribe, () => enteredGroup.get() !== null);\n const filtering = anyEntered || isPointerInteractive !== undefined;\n const reachable = useMemo(() => {\n if (!filtering) return undefined;\n const scope = createEnteredGroupScope({ entered: enteredGroup, scene });\n return (id: string) => scope.isPointerInteractive(id) && consumerInteractive.current?.(id) !== false;\n }, [filtering, enteredGroup, scene, consumerInteractive]);\n\n const surfaceViewRegistry = useOptionalViewRegistry();\n const viewLayerGate = useViewLayerGate(\n layerVisibility, layerOrder, () => surfaceViewRegistry?.surface()?.layers() ?? [],\n );\n\n const depRegistry = useOptionalDepRegistry();\n const pasteInto = useCallback(() => depRegistry?.get('insertInto')?.get() ?? null, [depRegistry]);\n const adapter = useSceneAdapter(scene, {\n // `adapterMethods` is memoized; `selection` itself is a fresh object each render.\n selection: selection.adapterMethods,\n poseDescriptor: descriptor,\n pasteInto,\n });\n\n const selectTool = useSceneSelectTool({\n scene,\n adapter,\n poseDescriptor: descriptor,\n geometry,\n // The pick tolerance is declared in screen pixels; this is what converts it.\n getView: () => viewRef.current,\n // Only when the consumer actually fades something. Without a prop the\n // composed function is just the override lookup, and the source resolves\n // that once per walk instead of once per candidate.\n ...(alphaFor ? { alphaOf: composedAlphaFor } : {}),\n ...(viewLayerGate ? { layerIsPainted: viewLayerGate } : {}),\n ...(reachable ? { isPointerInteractive: reachable } : {}),\n selectTool: args.selectTool,\n });\n\n const getNodeAtPoint = useNodeAtPoint({\n pickBest: selectTool.pickBest, nodes: adapter, kindOf,\n });\n\n const doubleClickNames = useMemo(() => kindOfNode && ((hitId: string) => doubleClickTarget(hitId, {\n parentOf: (id) => scene.get(asNodeId(id))?.parent ?? null,\n kindOf: kindOfNode,\n scope: enteredGroup.get(),\n })), [scene, kindOfNode, enteredGroup]);\n\n return {\n ...selectTool, adapter, kindOfNode, doubleClickNames, getNodeAtPoint, viewLayerGate, enteredGroup,\n /** What a press or a region select can reach, or undefined when that is every node. */\n reachable,\n /** The composed paint alpha, only when the consumer fades anything. */\n alphaOf: alphaFor ? composedAlphaFor : undefined,\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AA4BA,SAAgB,gBAAqD,MAQlE;CACD,MAAM,EAAE,OAAO,WAAW,YAAY,YAAY;CAClD,MAAM,EAAE,UAAU,UAAU,iBAAiB,YAAY,yBAAyB,KAAK;CACvF,MAAM,EAAE,QAAQ,eAAe,KAAK;CAKpC,MAAM,mBAAmB,cACjB,gBAAgB,OAAO,QAAQ,GACrC,CAAC,OAAO,QAAQ,CAClB;CACA,MAAM,aAAa,gBAAgB,KAAK;CACxC,MAAM,eAAe,KAAK,MAAM,gBAAgB;CAGhD,MAAM,sBAAsB,UAAU,oBAAoB;CAE1D,MAAM,YADa,qBAAqB,aAAa,iBAAiB,aAAa,IAAI,MAAM,IAC3E,KAAc,yBAAyB;CACzD,MAAM,YAAY,cAAc;EAC9B,IAAI,CAAC,WAAW,OAAO;EACvB,MAAM,QAAQ,wBAAwB;GAAE,SAAS;GAAc;EAAM,CAAC;EACtE,QAAQ,OAAe,MAAM,qBAAqB,EAAE,KAAK,oBAAoB,UAAU,EAAE,MAAM;CACjG,GAAG;EAAC;EAAW;EAAc;EAAO;CAAmB,CAAC;CAExD,MAAM,sBAAsB,wBAAwB;CACpD,MAAM,gBAAgB,iBACpB,iBAAiB,kBAAkB,qBAAqB,QAAQ,CAAC,EAAE,OAAO,KAAK,CAAC,CAClF;CAEA,MAAM,cAAc,uBAAuB;CAC3C,MAAM,YAAY,kBAAkB,aAAa,IAAI,YAAY,CAAC,EAAE,IAAI,KAAK,MAAM,CAAC,WAAW,CAAC;CAChG,MAAM,UAAU,gBAAgB,OAAO;EAErC,WAAW,UAAU;EACrB,gBAAgB;EAChB;CACF,CAAC;CAED,MAAM,aAAa,mBAAmB;EACpC;EACA;EACA,gBAAgB;EAChB;EAEA,eAAe,QAAQ;EAIvB,GAAI,WAAW,EAAE,SAAS,iBAAiB,IAAI,CAAC;EAChD,GAAI,gBAAgB,EAAE,gBAAgB,cAAc,IAAI,CAAC;EACzD,GAAI,YAAY,EAAE,sBAAsB,UAAU,IAAI,CAAC;EACvD,YAAY,KAAK;CACnB,CAAC;CAED,MAAM,iBAAiB,eAAe;EACpC,UAAU,WAAW;EAAU,OAAO;EAAS;CACjD,CAAC;CAED,MAAM,mBAAmB,cAAc,gBAAgB,UAAkB,kBAAkB,OAAO;EAChG,WAAW,OAAO,MAAM,IAAI,SAAS,EAAE,CAAC,CAAC,EAAE,UAAU;EACrD,QAAQ;EACR,OAAO,aAAa,IAAI;CAC1B,CAAC,IAAI;EAAC;EAAO;EAAY;CAAY,CAAC;CAEtC,OAAO;EACL,GAAG;EAAY;EAAS;EAAY;EAAkB;EAAgB;EAAe;;EAErF;;EAEA,SAAS,WAAW,mBAAmB;CACzC;AACF"}
1
+ {"version":3,"file":"useScenePicking.js","names":[],"sources":["../../../src/canvas/SceneCanvas/useScenePicking.ts"],"sourcesContent":["import { useCallback, useMemo, type RefObject } from 'react';\nimport { useOptionalDepRegistry } from '@weasel-js/routing/react';\nimport { asNodeId, type Scene } from 'core/scene/types';\nimport { useLatest } from '@weasel-js/react';\nimport { doubleClickTarget } from '../doubleClickTarget';\nimport { useEnteredGroup } from '../deps/enteredGroup';\nimport { createEnteredGroupScope } from 'domains/selection/enteredGroupScope';\nimport type { SelectionApi } from 'core/selection/useSelection';\nimport type { View } from 'core/viewport/view';\nimport type { PoseDescriptor } from 'interactions/actions/resize/geometry';\nimport { composeAlphaFor } from '../sceneSlotWiring';\nimport { useSceneAdapter } from '../useSceneAdapter';\nimport type { SceneCanvasProps } from './props';\nimport { useNodeAtPoint } from './useNodeAtPoint';\nimport type { NodeKinds } from './useNodeKinds';\nimport { useSceneSelectTool, type UseSceneSelectToolArgs } from './useSceneSelectTool';\nimport { useOptionalViewRegistry } from '../viewRegistry';\nimport { useViewLayerGate } from '../useViewLayerGate';\n\ntype PickingProps<TData, TLayer extends string, TPose> = Pick<\n SceneCanvasProps<TData, TLayer, TPose>,\n 'geometry' | 'alphaFor' | 'layerVisibility' | 'layerOrder' | 'isPointerInteractive' | 'enteredGroup'\n>;\n\n/**\n * The canvas's adapter and everything that answers \"what is under this point\": the select\n * tool's pickers and bounds, the node kinds, and the paint gates picking shares with the painter.\n */\nexport function useScenePicking<TData, TLayer extends string, TPose>(args: {\n scene: Scene<TData, TLayer, TPose>;\n selection: SelectionApi;\n descriptor: PoseDescriptor<TPose>;\n props: PickingProps<TData, TLayer, TPose>;\n viewRef: RefObject<View>;\n selectTool: UseSceneSelectToolArgs<TData, TLayer, TPose>['selectTool'];\n kinds: NodeKinds<TData>;\n}) {\n const { scene, selection, descriptor, viewRef } = args;\n const { geometry, alphaFor, layerVisibility, layerOrder, isPointerInteractive } = args.props;\n const { kindOf, kindOfNode } = args.kinds;\n\n // The painted alpha of a node in this view: the caller's `alphaFor` times any per-node\n // override alpha. The pick path reads the same number the painter does, or a node faded\n // to nothing stays clickable.\n const composedAlphaFor = useMemo(\n () => composeAlphaFor(scene, alphaFor),\n [scene, alphaFor],\n );\n const ownEntered = useEnteredGroup(scene);\n const enteredGroup = args.props.enteredGroup ?? ownEntered;\n // A press resolves inside the entered group, so nothing outside it takes a hit, and nothing a\n // node consumes takes one until that node is entered.\n const consumerInteractive = useLatest(isPointerInteractive);\n const reachable = useMemo(() => {\n const scope = createEnteredGroupScope({ entered: enteredGroup, scene });\n return (id: string) => scope.isPointerInteractive(id) && consumerInteractive.current?.(id) !== false;\n }, [enteredGroup, scene, consumerInteractive]);\n\n const surfaceViewRegistry = useOptionalViewRegistry();\n const viewLayerGate = useViewLayerGate(\n layerVisibility, layerOrder, () => surfaceViewRegistry?.surface()?.layers() ?? [],\n );\n\n const depRegistry = useOptionalDepRegistry();\n const pasteInto = useCallback(() => depRegistry?.get('insertInto')?.get() ?? null, [depRegistry]);\n const adapter = useSceneAdapter(scene, {\n // `adapterMethods` is memoized; `selection` itself is a fresh object each render.\n selection: selection.adapterMethods,\n poseDescriptor: descriptor,\n pasteInto,\n });\n\n const selectTool = useSceneSelectTool({\n scene,\n adapter,\n poseDescriptor: descriptor,\n geometry,\n // The pick tolerance is declared in screen pixels; this is what converts it.\n getView: () => viewRef.current,\n // Only when the consumer actually fades something. Without a prop the\n // composed function is just the override lookup, and the source resolves\n // that once per walk instead of once per candidate.\n ...(alphaFor ? { alphaOf: composedAlphaFor } : {}),\n ...(viewLayerGate ? { layerIsPainted: viewLayerGate } : {}),\n isPointerInteractive: reachable,\n selectTool: args.selectTool,\n });\n\n const getNodeAtPoint = useNodeAtPoint({\n pickBest: selectTool.pickBest, nodes: adapter, kindOf,\n });\n\n const doubleClickNames = useMemo(() => kindOfNode && ((hitId: string) => doubleClickTarget(hitId, {\n parentOf: (id) => scene.get(asNodeId(id))?.parent ?? null,\n kindOf: kindOfNode,\n scope: enteredGroup.get(),\n })), [scene, kindOfNode, enteredGroup]);\n\n return {\n ...selectTool, adapter, kindOfNode, doubleClickNames, getNodeAtPoint, viewLayerGate, enteredGroup,\n /** What a press or a region select can reach. */\n reachable,\n /** The composed paint alpha, only when the consumer fades anything. */\n alphaOf: alphaFor ? composedAlphaFor : undefined,\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AA4BA,SAAgB,gBAAqD,MAQlE;CACD,MAAM,EAAE,OAAO,WAAW,YAAY,YAAY;CAClD,MAAM,EAAE,UAAU,UAAU,iBAAiB,YAAY,yBAAyB,KAAK;CACvF,MAAM,EAAE,QAAQ,eAAe,KAAK;CAKpC,MAAM,mBAAmB,cACjB,gBAAgB,OAAO,QAAQ,GACrC,CAAC,OAAO,QAAQ,CAClB;CACA,MAAM,aAAa,gBAAgB,KAAK;CACxC,MAAM,eAAe,KAAK,MAAM,gBAAgB;CAGhD,MAAM,sBAAsB,UAAU,oBAAoB;CAC1D,MAAM,YAAY,cAAc;EAC9B,MAAM,QAAQ,wBAAwB;GAAE,SAAS;GAAc;EAAM,CAAC;EACtE,QAAQ,OAAe,MAAM,qBAAqB,EAAE,KAAK,oBAAoB,UAAU,EAAE,MAAM;CACjG,GAAG;EAAC;EAAc;EAAO;CAAmB,CAAC;CAE7C,MAAM,sBAAsB,wBAAwB;CACpD,MAAM,gBAAgB,iBACpB,iBAAiB,kBAAkB,qBAAqB,QAAQ,CAAC,EAAE,OAAO,KAAK,CAAC,CAClF;CAEA,MAAM,cAAc,uBAAuB;CAC3C,MAAM,YAAY,kBAAkB,aAAa,IAAI,YAAY,CAAC,EAAE,IAAI,KAAK,MAAM,CAAC,WAAW,CAAC;CAChG,MAAM,UAAU,gBAAgB,OAAO;EAErC,WAAW,UAAU;EACrB,gBAAgB;EAChB;CACF,CAAC;CAED,MAAM,aAAa,mBAAmB;EACpC;EACA;EACA,gBAAgB;EAChB;EAEA,eAAe,QAAQ;EAIvB,GAAI,WAAW,EAAE,SAAS,iBAAiB,IAAI,CAAC;EAChD,GAAI,gBAAgB,EAAE,gBAAgB,cAAc,IAAI,CAAC;EACzD,sBAAsB;EACtB,YAAY,KAAK;CACnB,CAAC;CAED,MAAM,iBAAiB,eAAe;EACpC,UAAU,WAAW;EAAU,OAAO;EAAS;CACjD,CAAC;CAED,MAAM,mBAAmB,cAAc,gBAAgB,UAAkB,kBAAkB,OAAO;EAChG,WAAW,OAAO,MAAM,IAAI,SAAS,EAAE,CAAC,CAAC,EAAE,UAAU;EACrD,QAAQ;EACR,OAAO,aAAa,IAAI;CAC1B,CAAC,IAAI;EAAC;EAAO;EAAY;CAAY,CAAC;CAEtC,OAAO;EACL,GAAG;EAAY;EAAS;EAAY;EAAkB;EAAgB;EAAe;;EAErF;;EAEA,SAAS,WAAW,mBAAmB;CACzC;AACF"}
@@ -5,7 +5,7 @@ import { useMemo } from "react";
5
5
  * What repaints a `<SceneCanvas>` besides its own render: the caller's
6
6
  * sources, then the canvas's. Neither a scene write nor an override write
7
7
  * renders the component, and an override write does not bump the scene version
8
- * either. An animator frame repaints for a `drawOne` reading
8
+ * either; nor does a scroll. An animator frame repaints for a `drawOne` reading
9
9
  * `animator.colorOverrides`.
10
10
  */
11
11
  function useSceneRedrawSources(args) {
@@ -15,6 +15,7 @@ function useSceneRedrawSources(args) {
15
15
  ...supplied ?? [],
16
16
  scene,
17
17
  scene.overrides,
18
+ ...scene.scroll ? [scene.scroll] : [],
18
19
  heldModifiers,
19
20
  ...animator ? [{ subscribe: (repaint) => animator.onTick(repaint) }] : [],
20
21
  ...modes ? [modes] : [],
@@ -1 +1 @@
1
- {"version":3,"file":"useSceneRedrawSources.js","names":[],"sources":["../../../src/canvas/SceneCanvas/useSceneRedrawSources.ts"],"sourcesContent":["import { useMemo } from 'react';\nimport type { RedrawSource } from '../../core/layers/render';\n\n/**\n * What repaints a `<SceneCanvas>` besides its own render: the caller's\n * sources, then the canvas's. Neither a scene write nor an override write\n * renders the component, and an override write does not bump the scene version\n * either. An animator frame repaints for a `drawOne` reading\n * `animator.colorOverrides`.\n */\nexport function useSceneRedrawSources(args: {\n /** `<SceneCanvas>`'s own `redrawOn`, `animator` and `modes`. */\n props: {\n redrawOn?: readonly RedrawSource[];\n animator?: { onTick(listener: () => void): () => void };\n modes?: RedrawSource;\n };\n scene: RedrawSource & { overrides: RedrawSource };\n heldModifiers: RedrawSource;\n /** The ghosts `poseTransition` shows leaving, which move each frame. */\n departures: RedrawSource;\n}): readonly RedrawSource[] {\n const { scene, heldModifiers, departures } = args;\n const { redrawOn: supplied, animator, modes } = args.props;\n return useMemo((): readonly RedrawSource[] => [\n ...(supplied ?? []),\n scene,\n scene.overrides,\n heldModifiers,\n ...(animator ? [{ subscribe: (repaint: () => void) => animator.onTick(repaint) }] : []),\n ...(modes ? [modes] : []),\n departures,\n ], [scene, heldModifiers, animator, modes, supplied, departures]);\n}\n"],"mappings":";;;;;;;;;;AAUA,SAAgB,sBAAsB,MAWV;CAC1B,MAAM,EAAE,OAAO,eAAe,eAAe;CAC7C,MAAM,EAAE,UAAU,UAAU,UAAU,UAAU,KAAK;CACrD,OAAO,cAAuC;EAC5C,GAAI,YAAY,CAAC;EACjB;EACA,MAAM;EACN;EACA,GAAI,WAAW,CAAC,EAAE,YAAY,YAAwB,SAAS,OAAO,OAAO,EAAE,CAAC,IAAI,CAAC;EACrF,GAAI,QAAQ,CAAC,KAAK,IAAI,CAAC;EACvB;CACF,GAAG;EAAC;EAAO;EAAe;EAAU;EAAO;EAAU;CAAU,CAAC;AAClE"}
1
+ {"version":3,"file":"useSceneRedrawSources.js","names":[],"sources":["../../../src/canvas/SceneCanvas/useSceneRedrawSources.ts"],"sourcesContent":["import { useMemo } from 'react';\nimport type { RedrawSource } from '../../core/layers/render';\n\n/**\n * What repaints a `<SceneCanvas>` besides its own render: the caller's\n * sources, then the canvas's. Neither a scene write nor an override write\n * renders the component, and an override write does not bump the scene version\n * either; nor does a scroll. An animator frame repaints for a `drawOne` reading\n * `animator.colorOverrides`.\n */\nexport function useSceneRedrawSources(args: {\n /** `<SceneCanvas>`'s own `redrawOn`, `animator` and `modes`. */\n props: {\n redrawOn?: readonly RedrawSource[];\n animator?: { onTick(listener: () => void): () => void };\n modes?: RedrawSource;\n };\n scene: RedrawSource & { overrides: RedrawSource; scroll?: RedrawSource };\n heldModifiers: RedrawSource;\n /** The ghosts `poseTransition` shows leaving, which move each frame. */\n departures: RedrawSource;\n}): readonly RedrawSource[] {\n const { scene, heldModifiers, departures } = args;\n const { redrawOn: supplied, animator, modes } = args.props;\n return useMemo((): readonly RedrawSource[] => [\n ...(supplied ?? []),\n scene,\n scene.overrides,\n ...(scene.scroll ? [scene.scroll] : []),\n heldModifiers,\n ...(animator ? [{ subscribe: (repaint: () => void) => animator.onTick(repaint) }] : []),\n ...(modes ? [modes] : []),\n departures,\n ], [scene, heldModifiers, animator, modes, supplied, departures]);\n}\n"],"mappings":";;;;;;;;;;AAUA,SAAgB,sBAAsB,MAWV;CAC1B,MAAM,EAAE,OAAO,eAAe,eAAe;CAC7C,MAAM,EAAE,UAAU,UAAU,UAAU,UAAU,KAAK;CACrD,OAAO,cAAuC;EAC5C,GAAI,YAAY,CAAC;EACjB;EACA,MAAM;EACN,GAAI,MAAM,SAAS,CAAC,MAAM,MAAM,IAAI,CAAC;EACrC;EACA,GAAI,WAAW,CAAC,EAAE,YAAY,YAAwB,SAAS,OAAO,OAAO,EAAE,CAAC,IAAI,CAAC;EACrF,GAAI,QAAQ,CAAC,KAAK,IAAI,CAAC;EACvB;CACF,GAAG;EAAC;EAAO;EAAe;EAAU;EAAO;EAAU;CAAU,CAAC;AAClE"}
@@ -112,8 +112,8 @@ function useSceneSelectTool(args) {
112
112
  }),
113
113
  pickEvery: wiredHitBody,
114
114
  pickBest: useMemo(() => {
115
- return (wx, wy, view) => {
116
- const ids = wiredHitBody(wx, wy, view);
115
+ return (world, view) => {
116
+ const ids = wiredHitBody(world, view);
117
117
  return pickTopMostHit(ids, adapter);
118
118
  };
119
119
  }, [wiredHitBody, adapter]),
@@ -128,9 +128,9 @@ function useSceneSelectTool(args) {
128
128
  function usePointPick(args) {
129
129
  const { scene, d, pickEveryProp, shapePicking, pickTolerancePx, getView, alphaOf, layerIsPainted, isPointerInteractive } = args;
130
130
  const walk = useMemo(() => {
131
- return (wx, wy, view) => {
131
+ return (world, view) => {
132
132
  if (pickEveryProp) {
133
- const r = pickEveryProp(wx, wy);
133
+ const r = pickEveryProp(world);
134
134
  if (r == null) return [];
135
135
  return Array.isArray(r) ? r : [r];
136
136
  }
@@ -145,7 +145,7 @@ function usePointPick(args) {
145
145
  ...camera ? { camera } : {}
146
146
  });
147
147
  const pointQuery = scenePointQuery(d, shapePicking, pickTolerancePx);
148
- return pickWalk(src, pointQuery(wx, wy, asked?.scale ?? {
148
+ return pickWalk(src, pointQuery(world.x, world.y, asked?.scale ?? {
149
149
  x: 1,
150
150
  y: 1
151
151
  }));
@@ -162,7 +162,7 @@ function usePointPick(args) {
162
162
  ]);
163
163
  return useMemo(() => {
164
164
  if (!isPointerInteractive) return walk;
165
- return (wx, wy, view) => walk(wx, wy, view).filter((id) => isPointerInteractive(id) !== false);
165
+ return (world, view) => walk(world, view).filter((id) => isPointerInteractive(id) !== false);
166
166
  }, [walk, isPointerInteractive]);
167
167
  }
168
168
 
@@ -1 +1 @@
1
- {"version":3,"file":"useSceneSelectTool.js","names":[],"sources":["../../../src/canvas/SceneCanvas/useSceneSelectTool.ts"],"sourcesContent":["/**\n * Scene-aware select-tool synthesis for `<SceneCanvas>`: a `useSelectTool`\n * over the caller's scene adapter, configured with kit-default pickEvery /\n * boundsOf derived from pose shape. Caller-supplied `pickEvery` / `boundsOf`\n * overrides via the `geometry` arg take precedence.\n */\nimport { drawnBoundsScene } from '../derivedPath';\nimport { useMemo } from 'react';\nimport { useKitSetting, useLatest } from '@weasel-js/react';\nimport type { SceneCanvasAdapter } from '../sceneAdapter';\nimport { pickWalk, scenePickSource, scenePlaneOf, type ViewPickGates } from 'canvas/pickWalk';\nimport { rectFromPlane, type PlaneMap } from 'core/viewport/parallax';\nimport type { View } from 'core/viewport/view';\nimport { useSelectTool, type Bounds } from 'tools/builtin/select';\nimport { pickTopMostHit, type PickTopMostHitAdapter } from 'tools/builtin/pickTopMostHit';\nimport type { Node, Scene } from 'core/scene/types';\nimport { asNodeId } from 'core/scene/types';\nimport type { UseMoveOptions } from 'interactions/actions/move/options';\nimport type { UseResizeOptions } from 'interactions/actions/resize/options';\nimport type { PoseDescriptor } from 'interactions/actions/resize/geometry';\nimport { drawnBoundsOf } from 'canvas/drawnBounds';\nimport { AUTO_POSE_DESCRIPTOR } from 'core/geometry/autoPoseDescriptor';\nimport { scenePointQuery } from './scenePointQuery';\nimport type { SceneCanvasGeometry } from './geometryProps';\n\n/**\n * Default grab slop around a shape's outline, in screen pixels.\n *\n * Four is the same number the path-pose stroke test has always used, and it's\n * the difference between a hairline being clickable and not: a 1px stroke is\n * half a world unit of reach at scale 1, which no pointing device can hit\n * reliably. It also lets a filled shape be grabbed a few pixels outside its\n * edge, which is what makes edge-adjacent dragging feel possible.\n */\nexport const DEFAULT_PICK_TOLERANCE_PX = 4;\n\n/** The view a pick is asked for. A world point carries neither the scale it\n * was produced under nor what that view paints, so a caller picking for a\n * view other than the surface's says both. A gate left out is the one this\n * hook was built with. */\nexport interface PickView extends ViewPickGates {\n scale: { x: number; y: number };\n /** The rest of the asking camera. Supplied, it lets a parallax layer be\n * picked through its plane; left out, every layer is taken to move with\n * the camera. */\n x?: number;\n y?: number;\n}\n\n/** A pick view that names a whole camera, or null. */\nfunction cameraOf(v: Pick<PickView, 'scale' | 'x' | 'y'> | null): View | null {\n return v && typeof v.x === 'number' && typeof v.y === 'number'\n ? { x: v.x, y: v.y, scale: v.scale }\n : null;\n}\n\nexport interface UseSceneSelectToolArgs<TData, TLayer extends string, TPose> {\n scene: Scene<TData, TLayer, TPose>;\n /** The adapter the select tool drives, built over `scene` with the same\n * `poseDescriptor`. Its world poses are what bounds read, and equal the\n * scene's painted poses, which picking reads. */\n adapter: SceneCanvasAdapter<TData, TLayer, TPose>;\n /** How to read and rewrite this scene's poses. Default `AUTO_POSE_DESCRIPTOR`. */\n poseDescriptor?: PoseDescriptor<TPose>;\n geometry?: SceneCanvasGeometry;\n /** The surface's camera, for converting the screen-pixel pick tolerance into\n * world units. A caller picking for another view passes that view's camera\n * to `pickEvery` / `pickBest` instead. Omitted in tests and non-viewport\n * hosts, where scale is 1. */\n getView?: () => Pick<PickView, 'scale' | 'x' | 'y'> | null;\n /** The asking view's painted alpha per node — its `alphaFor` times any\n * per-node override alpha. A node the view paints at alpha 0 is not on\n * screen, so picking must not answer for it. */\n alphaOf?: (id: string) => number;\n /** The asking view's answer to \"does this scene layer reach the screen\".\n * `layerVisibility` and `layerOrder` both gate a layer out of the paint\n * (`drawLayers` drops any layer missing from a supplied order), and an\n * undrawn layer must not claim clicks. */\n layerIsPainted?: (layer: string) => boolean;\n /** `<SceneCanvas isPointerInteractive>`: a node it rejects is left out of every hit, so\n * whatever is beneath it answers instead. */\n isPointerInteractive?: (id: string) => boolean;\n selectTool?: {\n move?: UseMoveOptions<TPose>;\n resize?: UseResizeOptions<TPose>;\n /** Override the body-pick used on click/pointerdown. Alt-aware: receives\n * the live alt state + current selection so consumers can implement\n * alt-cycling through an overlapping stack. Default: top-most hit\n * (alt ignored). Forwarded verbatim to `useSelectTool`. */\n pickBest?: (worldX: number, worldY: number, alt: boolean, sel: readonly string[]) => string | null;\n /** Forwarded verbatim to `useSelectTool`. See\n * `UseSelectToolOptions.extendClickLocked`. */\n extendClickLocked?: () => boolean;\n };\n}\n\n/** `id` drawn at `pose`, in world, as the chrome boxes it. */\nfunction chromeBox<TData, TLayer extends string, TPose>(\n scene: Scene<TData, TLayer, TPose>,\n adapter: SceneCanvasAdapter<TData, TLayer, TPose>,\n descriptor: PoseDescriptor<TPose>,\n includeStroke: boolean,\n id: string,\n pose: TPose,\n scale: { x: number; y: number } | undefined,\n): Bounds {\n return drawnBoundsOf(drawnBoundsScene(scene), asNodeId(id), pose, {\n descriptor: descriptor as PoseDescriptor<unknown>,\n worldPoseOf: (m) => adapter.getWorldPose(m),\n includeStroke,\n ...(scale ? { scale } : {}),\n });\n}\n\nexport interface UseSceneSelectToolReturn<TData, TLayer extends string, TPose> {\n selectTool: ReturnType<typeof useSelectTool<Node<TData, TLayer, TPose>, TPose>>;\n /** Every id under the world point, back-to-front (topmost last), from the\n * caller's `geometry.pickEvery` or the pose-walk default. */\n pickEvery: (worldX: number, worldY: number, view?: PickView | null) => string[];\n /** Single-best hit under the world point, or null. Runs `pickEvery` then\n * collapses parent/child overlap via `pickTopMostHit` — matches the id\n * the select tool's pointerdown classifier would settle on for a bare\n * click. The canvas's `getNodeAtPoint` resolves through it. */\n pickBest: (worldX: number, worldY: number, view?: PickView | null) => string | null;\n /** World-space AABB of `id`, or null. Same as what the selection overlay +\n * affordance hit-test need. Exposed so SceneCanvas can pass it to the\n * `affordanceAt` thunk without re-deriving it. `view` is the camera the\n * box is drawn under — a plane node sits somewhere else in each — and\n * defaults to the surface's. */\n boundsOf: (id: string, view?: Pick<PickView, 'scale' | 'x' | 'y'> | null) =>\n import('core/viewport/fitViewToBounds').Bounds | null;\n /** How `view`'s world (the surface's camera by default) maps into the plane\n * `id` is drawn through, or null when its layer moves with the camera. */\n planeOfNode: (id: string, view?: Pick<PickView, 'scale' | 'x' | 'y'> | null) => PlaneMap | null;\n /** `boundsOf` for `id` drawn at `pose` rather than its own — how chrome\n * boxes an in-flight preview. Ignores a `geometry.boundsOf` override, which\n * answers only for a node's own pose. */\n boundsOfPose: (id: string, pose: TPose, view?: Pick<PickView, 'scale' | 'x' | 'y'> | null) =>\n import('core/viewport/fitViewToBounds').Bounds | null;\n /** `selectTool.move` — what the `move` preset's bindings carry. */\n moveOptions: UseMoveOptions<TPose>;\n}\n\nexport function useSceneSelectTool<TData, TLayer extends string, TPose>(\n args: UseSceneSelectToolArgs<TData, TLayer, TPose>,\n): UseSceneSelectToolReturn<TData, TLayer, TPose> {\n const { scene, adapter, geometry, selectTool: opts, getView, alphaOf, layerIsPainted, isPointerInteractive } = args;\n const d = (args.poseDescriptor ?? AUTO_POSE_DESCRIPTOR) as PoseDescriptor<TPose>;\n\n const pickEveryProp = geometry?.pickEvery;\n const boundsOfProp = geometry?.boundsOf;\n // Default. The pose rect is the wrong answer for anything that isn't a rectangle, so `'pose'`\n // is the opt-out rather than the baseline. Cheap to leave on: the rect pre-filter rejects every\n // node the pointer isn't over first, and the survivors' silhouettes are memoized per node.\n const shapePicking = (geometry?.picking ?? 'shape') === 'shape';\n const kitPickTolerancePx = useKitSetting('targets.pickTolerancePx');\n const pickTolerancePx = geometry?.pickTolerancePx ?? kitPickTolerancePx ?? DEFAULT_PICK_TOLERANCE_PX;\n const includeStroke = geometry?.boundsIncludeStroke ?? true;\n const moveOptions = opts?.move;\n const wiredMoveOptions = useMemo<UseMoveOptions<TPose>>(() => moveOptions ?? {}, [moveOptions]);\n\n const wiredHitBody = usePointPick({\n scene, d, pickEveryProp, shapePicking, pickTolerancePx, getView,\n alphaOf, layerIsPainted, isPointerInteractive,\n });\n\n // Read through a ref: this is the chrome's bounds source, and a caller's\n // inline `getView` would otherwise rebuild it, and everything keyed on it,\n // every render.\n const getViewRef = useLatest(getView);\n const wiredPlaneOfNode = useMemo(() => {\n return (id: string, view?: Pick<PickView, 'scale' | 'x' | 'y'> | null): PlaneMap | null => {\n const n = scene.get(asNodeId(id));\n const camera = cameraOf(view ?? getViewRef.current?.() ?? null);\n if (!n || !camera) return null;\n return scenePlaneOf(scene.layers, camera)?.(n.layer) ?? null;\n };\n }, [scene, getViewRef]);\n\n const wiredBoundsOfPose = useMemo(() => {\n return (id: string, pose: TPose, view?: Pick<PickView, 'scale' | 'x' | 'y'> | null): Bounds | null => {\n if (!scene.get(asNodeId(id))) return null;\n const scale = (view ?? getViewRef.current?.() ?? null)?.scale;\n const own = chromeBox(scene, adapter, d, includeStroke, id, pose, scale);\n // A plane node is drawn where its plane puts it, and the chrome has to\n // follow it there.\n const plane = wiredPlaneOfNode(id, view);\n return plane ? rectFromPlane(plane, own) : own;\n };\n }, [scene, adapter, d, includeStroke, getViewRef, wiredPlaneOfNode]);\n\n const wiredBoundsOf = useMemo(() => {\n return (id: string, view?: Pick<PickView, 'scale' | 'x' | 'y'> | null): Bounds | null => {\n if (boundsOfProp) return boundsOfProp(id);\n if (!scene.get(asNodeId(id))) return null;\n // World, not local: a framed child is drawn in its parent's frame, and\n // the chrome has to land on the ink.\n return wiredBoundsOfPose(id, adapter.getWorldPose(id), view);\n };\n }, [scene, adapter, boundsOfProp, wiredBoundsOfPose]);\n\n const selectTool = useSelectTool<Node<TData, TLayer, TPose>, TPose>(adapter, {\n pickEvery: wiredHitBody,\n ...(opts?.pickBest ? { pickBest: opts.pickBest } : {}),\n ...(opts?.extendClickLocked ? { extendClickLocked: opts.extendClickLocked } : {}),\n });\n\n\n const wiredPickBest = useMemo(() => {\n return (wx: number, wy: number, view?: PickView | null): string | null => {\n const ids = wiredHitBody(wx, wy, view);\n return pickTopMostHit(ids, adapter as unknown as PickTopMostHitAdapter);\n };\n }, [wiredHitBody, adapter]);\n\n return {\n selectTool,\n pickEvery: wiredHitBody,\n pickBest: wiredPickBest,\n boundsOf: wiredBoundsOf,\n boundsOfPose: wiredBoundsOfPose,\n planeOfNode: wiredPlaneOfNode,\n moveOptions: wiredMoveOptions,\n };\n}\n\n/** Every id under a world point, back-to-front: the caller's `geometry.pickEvery` or the pose\n * walk, less whatever `isPointerInteractive` rejects. */\nfunction usePointPick<TData, TLayer extends string, TPose>(args: {\n scene: Scene<TData, TLayer, TPose>;\n d: PoseDescriptor<TPose>;\n pickEveryProp: SceneCanvasGeometry['pickEvery'];\n shapePicking: boolean;\n pickTolerancePx: number;\n getView: UseSceneSelectToolArgs<TData, TLayer, TPose>['getView'];\n alphaOf: ((id: string) => number) | undefined;\n layerIsPainted: ((layer: string) => boolean) | undefined;\n isPointerInteractive: ((id: string) => boolean) | undefined;\n}): (wx: number, wy: number, view?: PickView | null) => string[] {\n const {\n scene, d, pickEveryProp, shapePicking, pickTolerancePx, getView,\n alphaOf, layerIsPainted, isPointerInteractive,\n } = args;\n // Default pickEvery: walk renderOrder() forward (back-to-front) and collect\n // every node whose pose contains the world point. Order matches the\n // `useSelectTool` contract — last element is the topmost — so `pickTopMostHit`\n // picks correctly. Wraps the caller's `pickEvery` (string-or-null) into the\n // array form `useSelectTool` expects. `poseContainsRotated` reads\n // `pose.rotation` directly (the kit's one rotation convention), so rotated\n // shapes pick against their rendered, rotated body without a per-demo override.\n const walk = useMemo(() => {\n return (wx: number, wy: number, view?: PickView | null): string[] => {\n if (pickEveryProp) {\n const r = pickEveryProp(wx, wy);\n if (r == null) return [];\n return Array.isArray(r) ? r : [r];\n }\n const asked = view ?? getView?.() ?? null;\n const viewAlpha = view?.alphaOf ?? alphaOf;\n const viewLayers = view?.layerIsPainted ?? layerIsPainted;\n const camera = cameraOf(asked);\n // No `getPose`: the scene's painted poses are the adapter's world poses\n // (`useSceneSelectTool.index.test.tsx`), and they let the index serve the walk.\n const src = scenePickSource<TData, TLayer, TPose>(scene, {\n index: { descriptor: d as PoseDescriptor<unknown> },\n ...(viewAlpha ? { alphaOf: viewAlpha } : {}),\n ...(viewLayers ? { layerIsPainted: viewLayers } : {}),\n ...(camera ? { camera } : {}),\n });\n const pointQuery = scenePointQuery<TPose>(d as PoseDescriptor<unknown>, shapePicking, pickTolerancePx);\n return pickWalk<TPose>(src, pointQuery(wx, wy, asked?.scale ?? { x: 1, y: 1 }));\n };\n }, [scene, pickEveryProp, shapePicking, pickTolerancePx, getView,\n alphaOf, layerIsPainted, d]);\n const wiredHitBody = useMemo(() => {\n if (!isPointerInteractive) return walk;\n return (wx: number, wy: number, view?: PickView | null): string[] =>\n walk(wx, wy, view).filter((id) => isPointerInteractive(id) !== false);\n }, [walk, isPointerInteractive]);\n return wiredHitBody;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"useSceneSelectTool.js","names":[],"sources":["../../../src/canvas/SceneCanvas/useSceneSelectTool.ts"],"sourcesContent":["/**\n * Scene-aware select-tool synthesis for `<SceneCanvas>`: a `useSelectTool`\n * over the caller's scene adapter, configured with kit-default pickEvery /\n * boundsOf derived from pose shape. Caller-supplied `pickEvery` / `boundsOf`\n * overrides via the `geometry` arg take precedence.\n */\nimport { drawnBoundsScene } from '../derivedPath';\nimport { useMemo } from 'react';\nimport { useKitSetting, useLatest } from '@weasel-js/react';\nimport type { SceneCanvasAdapter } from '../sceneAdapter';\nimport { pickWalk, scenePickSource, scenePlaneOf, type ViewPickGates } from 'canvas/pickWalk';\nimport { rectFromPlane, type PlaneMap } from 'core/viewport/parallax';\nimport type { View } from 'core/viewport/view';\nimport { useSelectTool, type Bounds } from 'tools/builtin/select';\nimport { pickTopMostHit, type PickTopMostHitAdapter } from 'tools/builtin/pickTopMostHit';\nimport type { Node, Scene } from 'core/scene/types';\nimport { asNodeId } from 'core/scene/types';\nimport type { UseMoveOptions } from 'interactions/actions/move/options';\nimport type { UseResizeOptions } from 'interactions/actions/resize/options';\nimport type { PoseDescriptor } from 'interactions/actions/resize/geometry';\nimport { drawnBoundsOf } from 'canvas/drawnBounds';\nimport { AUTO_POSE_DESCRIPTOR } from 'core/geometry/autoPoseDescriptor';\nimport { scenePointQuery } from './scenePointQuery';\nimport type { SceneCanvasGeometry } from './geometryProps';\nimport type { WorldPoint } from '@weasel-js/routing';\n\n/**\n * Default grab slop around a shape's outline, in screen pixels.\n *\n * Four is the same number the path-pose stroke test has always used, and it's\n * the difference between a hairline being clickable and not: a 1px stroke is\n * half a world unit of reach at scale 1, which no pointing device can hit\n * reliably. It also lets a filled shape be grabbed a few pixels outside its\n * edge, which is what makes edge-adjacent dragging feel possible.\n */\nexport const DEFAULT_PICK_TOLERANCE_PX = 4;\n\n/** The view a pick is asked for. A world point carries neither the scale it\n * was produced under nor what that view paints, so a caller picking for a\n * view other than the surface's says both. A gate left out is the one this\n * hook was built with. */\nexport interface PickView extends ViewPickGates {\n scale: { x: number; y: number };\n /** The rest of the asking camera. Supplied, it lets a parallax layer be\n * picked through its plane; left out, every layer is taken to move with\n * the camera. */\n x?: number;\n y?: number;\n}\n\n/** A pick view that names a whole camera, or null. */\nfunction cameraOf(v: Pick<PickView, 'scale' | 'x' | 'y'> | null): View | null {\n return v && typeof v.x === 'number' && typeof v.y === 'number'\n ? { x: v.x, y: v.y, scale: v.scale }\n : null;\n}\n\nexport interface UseSceneSelectToolArgs<TData, TLayer extends string, TPose> {\n scene: Scene<TData, TLayer, TPose>;\n /** The adapter the select tool drives, built over `scene` with the same\n * `poseDescriptor`. Its world poses are what bounds read, and equal the\n * scene's painted poses, which picking reads. */\n adapter: SceneCanvasAdapter<TData, TLayer, TPose>;\n /** How to read and rewrite this scene's poses. Default `AUTO_POSE_DESCRIPTOR`. */\n poseDescriptor?: PoseDescriptor<TPose>;\n geometry?: SceneCanvasGeometry;\n /** The surface's camera, for converting the screen-pixel pick tolerance into\n * world units. A caller picking for another view passes that view's camera\n * to `pickEvery` / `pickBest` instead. Omitted in tests and non-viewport\n * hosts, where scale is 1. */\n getView?: () => Pick<PickView, 'scale' | 'x' | 'y'> | null;\n /** The asking view's painted alpha per node — its `alphaFor` times any\n * per-node override alpha. A node the view paints at alpha 0 is not on\n * screen, so picking must not answer for it. */\n alphaOf?: (id: string) => number;\n /** The asking view's answer to \"does this scene layer reach the screen\".\n * `layerVisibility` and `layerOrder` both gate a layer out of the paint\n * (`drawLayers` drops any layer missing from a supplied order), and an\n * undrawn layer must not claim clicks. */\n layerIsPainted?: (layer: string) => boolean;\n /** `<SceneCanvas isPointerInteractive>`: a node it rejects is left out of every hit, so\n * whatever is beneath it answers instead. */\n isPointerInteractive?: (id: string) => boolean;\n selectTool?: {\n move?: UseMoveOptions<TPose>;\n resize?: UseResizeOptions<TPose>;\n /** Override the body-pick used on click/pointerdown. Alt-aware: receives\n * the live alt state + current selection so consumers can implement\n * alt-cycling through an overlapping stack. Default: top-most hit\n * (alt ignored). Forwarded verbatim to `useSelectTool`. */\n pickBest?: (world: WorldPoint, alt: boolean, sel: readonly string[]) => string | null;\n /** Forwarded verbatim to `useSelectTool`. See\n * `UseSelectToolOptions.extendClickLocked`. */\n extendClickLocked?: () => boolean;\n };\n}\n\n/** `id` drawn at `pose`, in world, as the chrome boxes it. */\nfunction chromeBox<TData, TLayer extends string, TPose>(\n scene: Scene<TData, TLayer, TPose>,\n adapter: SceneCanvasAdapter<TData, TLayer, TPose>,\n descriptor: PoseDescriptor<TPose>,\n includeStroke: boolean,\n id: string,\n pose: TPose,\n scale: { x: number; y: number } | undefined,\n): Bounds {\n return drawnBoundsOf(drawnBoundsScene(scene), asNodeId(id), pose, {\n descriptor: descriptor as PoseDescriptor<unknown>,\n worldPoseOf: (m) => adapter.getWorldPose(m),\n includeStroke,\n ...(scale ? { scale } : {}),\n });\n}\n\nexport interface UseSceneSelectToolReturn<TData, TLayer extends string, TPose> {\n selectTool: ReturnType<typeof useSelectTool<Node<TData, TLayer, TPose>, TPose>>;\n /** Every id under the world point, back-to-front (topmost last), from the\n * caller's `geometry.pickEvery` or the pose-walk default. */\n pickEvery: (world: WorldPoint, view?: PickView | null) => string[];\n /** Single-best hit under the world point, or null. Runs `pickEvery` then\n * collapses parent/child overlap via `pickTopMostHit` — matches the id\n * the select tool's pointerdown classifier would settle on for a bare\n * click. The canvas's `getNodeAtPoint` resolves through it. */\n pickBest: (world: WorldPoint, view?: PickView | null) => string | null;\n /** World-space AABB of `id`, or null. Same as what the selection overlay +\n * affordance hit-test need. Exposed so SceneCanvas can pass it to the\n * `affordanceAt` thunk without re-deriving it. `view` is the camera the\n * box is drawn under — a plane node sits somewhere else in each — and\n * defaults to the surface's. */\n boundsOf: (id: string, view?: Pick<PickView, 'scale' | 'x' | 'y'> | null) =>\n import('core/viewport/fitViewToBounds').Bounds | null;\n /** How `view`'s world (the surface's camera by default) maps into the plane\n * `id` is drawn through, or null when its layer moves with the camera. */\n planeOfNode: (id: string, view?: Pick<PickView, 'scale' | 'x' | 'y'> | null) => PlaneMap | null;\n /** `boundsOf` for `id` drawn at `pose` rather than its own — how chrome\n * boxes an in-flight preview. Ignores a `geometry.boundsOf` override, which\n * answers only for a node's own pose. */\n boundsOfPose: (id: string, pose: TPose, view?: Pick<PickView, 'scale' | 'x' | 'y'> | null) =>\n import('core/viewport/fitViewToBounds').Bounds | null;\n /** `selectTool.move` — what the `move` preset's bindings carry. */\n moveOptions: UseMoveOptions<TPose>;\n}\n\nexport function useSceneSelectTool<TData, TLayer extends string, TPose>(\n args: UseSceneSelectToolArgs<TData, TLayer, TPose>,\n): UseSceneSelectToolReturn<TData, TLayer, TPose> {\n const { scene, adapter, geometry, selectTool: opts, getView, alphaOf, layerIsPainted, isPointerInteractive } = args;\n const d = (args.poseDescriptor ?? AUTO_POSE_DESCRIPTOR) as PoseDescriptor<TPose>;\n\n const pickEveryProp = geometry?.pickEvery;\n const boundsOfProp = geometry?.boundsOf;\n // Default. The pose rect is the wrong answer for anything that isn't a rectangle, so `'pose'`\n // is the opt-out rather than the baseline. Cheap to leave on: the rect pre-filter rejects every\n // node the pointer isn't over first, and the survivors' silhouettes are memoized per node.\n const shapePicking = (geometry?.picking ?? 'shape') === 'shape';\n const kitPickTolerancePx = useKitSetting('targets.pickTolerancePx');\n const pickTolerancePx = geometry?.pickTolerancePx ?? kitPickTolerancePx ?? DEFAULT_PICK_TOLERANCE_PX;\n const includeStroke = geometry?.boundsIncludeStroke ?? true;\n const moveOptions = opts?.move;\n const wiredMoveOptions = useMemo<UseMoveOptions<TPose>>(() => moveOptions ?? {}, [moveOptions]);\n\n const wiredHitBody = usePointPick({\n scene, d, pickEveryProp, shapePicking, pickTolerancePx, getView,\n alphaOf, layerIsPainted, isPointerInteractive,\n });\n\n // Read through a ref: this is the chrome's bounds source, and a caller's\n // inline `getView` would otherwise rebuild it, and everything keyed on it,\n // every render.\n const getViewRef = useLatest(getView);\n const wiredPlaneOfNode = useMemo(() => {\n return (id: string, view?: Pick<PickView, 'scale' | 'x' | 'y'> | null): PlaneMap | null => {\n const n = scene.get(asNodeId(id));\n const camera = cameraOf(view ?? getViewRef.current?.() ?? null);\n if (!n || !camera) return null;\n return scenePlaneOf(scene.layers, camera)?.(n.layer) ?? null;\n };\n }, [scene, getViewRef]);\n\n const wiredBoundsOfPose = useMemo(() => {\n return (id: string, pose: TPose, view?: Pick<PickView, 'scale' | 'x' | 'y'> | null): Bounds | null => {\n if (!scene.get(asNodeId(id))) return null;\n const scale = (view ?? getViewRef.current?.() ?? null)?.scale;\n const own = chromeBox(scene, adapter, d, includeStroke, id, pose, scale);\n // A plane node is drawn where its plane puts it, and the chrome has to\n // follow it there.\n const plane = wiredPlaneOfNode(id, view);\n return plane ? rectFromPlane(plane, own) : own;\n };\n }, [scene, adapter, d, includeStroke, getViewRef, wiredPlaneOfNode]);\n\n const wiredBoundsOf = useMemo(() => {\n return (id: string, view?: Pick<PickView, 'scale' | 'x' | 'y'> | null): Bounds | null => {\n if (boundsOfProp) return boundsOfProp(id);\n if (!scene.get(asNodeId(id))) return null;\n // World, not local: a framed child is drawn in its parent's frame, and\n // the chrome has to land on the ink.\n return wiredBoundsOfPose(id, adapter.getWorldPose(id), view);\n };\n }, [scene, adapter, boundsOfProp, wiredBoundsOfPose]);\n\n const selectTool = useSelectTool<Node<TData, TLayer, TPose>, TPose>(adapter, {\n pickEvery: wiredHitBody,\n ...(opts?.pickBest ? { pickBest: opts.pickBest } : {}),\n ...(opts?.extendClickLocked ? { extendClickLocked: opts.extendClickLocked } : {}),\n });\n\n\n const wiredPickBest = useMemo(() => {\n return (world: WorldPoint, view?: PickView | null): string | null => {\n const ids = wiredHitBody(world, view);\n return pickTopMostHit(ids, adapter as unknown as PickTopMostHitAdapter);\n };\n }, [wiredHitBody, adapter]);\n\n return {\n selectTool,\n pickEvery: wiredHitBody,\n pickBest: wiredPickBest,\n boundsOf: wiredBoundsOf,\n boundsOfPose: wiredBoundsOfPose,\n planeOfNode: wiredPlaneOfNode,\n moveOptions: wiredMoveOptions,\n };\n}\n\n/** Every id under a world point, back-to-front: the caller's `geometry.pickEvery` or the pose\n * walk, less whatever `isPointerInteractive` rejects. */\nfunction usePointPick<TData, TLayer extends string, TPose>(args: {\n scene: Scene<TData, TLayer, TPose>;\n d: PoseDescriptor<TPose>;\n pickEveryProp: SceneCanvasGeometry['pickEvery'];\n shapePicking: boolean;\n pickTolerancePx: number;\n getView: UseSceneSelectToolArgs<TData, TLayer, TPose>['getView'];\n alphaOf: ((id: string) => number) | undefined;\n layerIsPainted: ((layer: string) => boolean) | undefined;\n isPointerInteractive: ((id: string) => boolean) | undefined;\n}): (world: WorldPoint, view?: PickView | null) => string[] {\n const {\n scene, d, pickEveryProp, shapePicking, pickTolerancePx, getView,\n alphaOf, layerIsPainted, isPointerInteractive,\n } = args;\n // Default pickEvery: walk renderOrder() forward (back-to-front) and collect\n // every node whose pose contains the world point. Order matches the\n // `useSelectTool` contract — last element is the topmost — so `pickTopMostHit`\n // picks correctly. Wraps the caller's `pickEvery` (string-or-null) into the\n // array form `useSelectTool` expects. `poseContainsRotated` reads\n // `pose.rotation` directly (the kit's one rotation convention), so rotated\n // shapes pick against their rendered, rotated body without a per-demo override.\n const walk = useMemo(() => {\n return (world: WorldPoint, view?: PickView | null): string[] => {\n if (pickEveryProp) {\n const r = pickEveryProp(world);\n if (r == null) return [];\n return Array.isArray(r) ? r : [r];\n }\n const asked = view ?? getView?.() ?? null;\n const viewAlpha = view?.alphaOf ?? alphaOf;\n const viewLayers = view?.layerIsPainted ?? layerIsPainted;\n const camera = cameraOf(asked);\n // No `getPose`: the scene's painted poses are the adapter's world poses\n // (`useSceneSelectTool.index.test.tsx`), and they let the index serve the walk.\n const src = scenePickSource<TData, TLayer, TPose>(scene, {\n index: { descriptor: d as PoseDescriptor<unknown> },\n ...(viewAlpha ? { alphaOf: viewAlpha } : {}),\n ...(viewLayers ? { layerIsPainted: viewLayers } : {}),\n ...(camera ? { camera } : {}),\n });\n const pointQuery = scenePointQuery<TPose>(d as PoseDescriptor<unknown>, shapePicking, pickTolerancePx);\n return pickWalk<TPose>(src, pointQuery(world.x, world.y, asked?.scale ?? { x: 1, y: 1 }));\n };\n }, [scene, pickEveryProp, shapePicking, pickTolerancePx, getView,\n alphaOf, layerIsPainted, d]);\n const wiredHitBody = useMemo(() => {\n if (!isPointerInteractive) return walk;\n return (world: WorldPoint, view?: PickView | null): string[] =>\n walk(world, view).filter((id) => isPointerInteractive(id) !== false);\n }, [walk, isPointerInteractive]);\n return wiredHitBody;\n}\n"],"mappings":"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"}