@weasel-js/core 1.11.1 → 1.13.0-rc.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 (488) hide show
  1. package/CHANGELOG.md +275 -0
  2. package/dist/WeaselProvider.js +1 -1
  3. package/dist/affordances/pathAnchors.js +10 -6
  4. package/dist/affordances/pathAnchors.js.map +1 -1
  5. package/dist/animation/poseTarget.js +46 -15
  6. package/dist/animation/poseTarget.js.map +1 -1
  7. package/dist/animation/poseTransition.js +3 -3
  8. package/dist/animation/poseTransition.js.map +1 -1
  9. package/dist/animation/reflow.js +3 -6
  10. package/dist/animation/reflow.js.map +1 -1
  11. package/dist/animation/rig/bindRig.js +2 -2
  12. package/dist/animation/rig/bindRig.js.map +1 -1
  13. package/dist/animation/rig/skinBinding.js +2 -2
  14. package/dist/animation/rig/skinBinding.js.map +1 -1
  15. package/dist/barrel/canvas.js +5 -1
  16. package/dist/barrel/chrome.js +3 -1
  17. package/dist/barrel/paint.js +4 -4
  18. package/dist/barrel/paths.js +9 -4
  19. package/dist/barrel/renderer.js +3 -2
  20. package/dist/barrel/routing.js +4 -4
  21. package/dist/barrel/scene.js +7 -1
  22. package/dist/barrel/text.js +2 -2
  23. package/dist/barrel/viewport.js +6 -2
  24. package/dist/canvas/Canvas.js +2 -1
  25. package/dist/canvas/Canvas.js.map +1 -1
  26. package/dist/canvas/CanvasView.js +23 -34
  27. package/dist/canvas/CanvasView.js.map +1 -1
  28. package/dist/canvas/ModalityHud.js +1 -1
  29. package/dist/canvas/NodeShape.js +5 -1
  30. package/dist/canvas/NodeShape.js.map +1 -1
  31. package/dist/canvas/SceneCanvas/ActionsProviderIfRoot.js +1 -1
  32. package/dist/canvas/SceneCanvas/DepRegistryProviderIfRoot.js +1 -1
  33. package/dist/canvas/SceneCanvas/PointerProviderIfRoot.js +1 -1
  34. package/dist/canvas/SceneCanvas/SceneCanvasInput.js +2 -0
  35. package/dist/canvas/SceneCanvas/SceneCanvasInput.js.map +1 -1
  36. package/dist/canvas/SceneCanvas/SurfaceDeclarations.js +23 -0
  37. package/dist/canvas/SceneCanvas/SurfaceDeclarations.js.map +1 -0
  38. package/dist/canvas/SceneCanvas/canvasPassThrough.js +2 -1
  39. package/dist/canvas/SceneCanvas/canvasPassThrough.js.map +1 -1
  40. package/dist/canvas/SceneCanvas/defaultNodeRouting.js +2 -2
  41. package/dist/canvas/SceneCanvas/defaultNodeRouting.js.map +1 -1
  42. package/dist/canvas/SceneCanvas/props.js.map +1 -1
  43. package/dist/canvas/SceneCanvas/scenePointQuery.js +27 -5
  44. package/dist/canvas/SceneCanvas/scenePointQuery.js.map +1 -1
  45. package/dist/canvas/SceneCanvas/useActionTunings.js +6 -1
  46. package/dist/canvas/SceneCanvas/useActionTunings.js.map +1 -1
  47. package/dist/canvas/SceneCanvas/useCanvasDevtoolsRoot.js +1 -0
  48. package/dist/canvas/SceneCanvas/useCanvasDevtoolsRoot.js.map +1 -1
  49. package/dist/canvas/SceneCanvas/useCanvasTools.js +10 -2
  50. package/dist/canvas/SceneCanvas/useCanvasTools.js.map +1 -1
  51. package/dist/canvas/SceneCanvas/usePreviewGhostLayer.js +25 -19
  52. package/dist/canvas/SceneCanvas/usePreviewGhostLayer.js.map +1 -1
  53. package/dist/canvas/SceneCanvas/useSceneCanvasHandle.js +9 -3
  54. package/dist/canvas/SceneCanvas/useSceneCanvasHandle.js.map +1 -1
  55. package/dist/canvas/SceneCanvas/useSceneCanvasLayers.js +17 -2
  56. package/dist/canvas/SceneCanvas/useSceneCanvasLayers.js.map +1 -1
  57. package/dist/canvas/SceneCanvas/useSceneCanvasTools.js +2 -0
  58. package/dist/canvas/SceneCanvas/useSceneCanvasTools.js.map +1 -1
  59. package/dist/canvas/SceneCanvas/useSceneGestureDispatcher.js +19 -4
  60. package/dist/canvas/SceneCanvas/useSceneGestureDispatcher.js.map +1 -1
  61. package/dist/canvas/SceneCanvas/useScenePicking.js +31 -6
  62. package/dist/canvas/SceneCanvas/useScenePicking.js.map +1 -1
  63. package/dist/canvas/SceneCanvas/useSceneSelectTool.js +4 -5
  64. package/dist/canvas/SceneCanvas/useSceneSelectTool.js.map +1 -1
  65. package/dist/canvas/SceneCanvas/useSceneStandardActions.js +7 -4
  66. package/dist/canvas/SceneCanvas/useSceneStandardActions.js.map +1 -1
  67. package/dist/canvas/SceneCanvas.js +30 -12
  68. package/dist/canvas/SceneCanvas.js.map +1 -1
  69. package/dist/canvas/ViewMarker.js +35 -0
  70. package/dist/canvas/ViewMarker.js.map +1 -0
  71. package/dist/canvas/accentColor.js +26 -3
  72. package/dist/canvas/accentColor.js.map +1 -1
  73. package/dist/canvas/buildSceneTree.js +14 -20
  74. package/dist/canvas/buildSceneTree.js.map +1 -1
  75. package/dist/canvas/copiesAbove.js +1 -1
  76. package/dist/canvas/copiesAbove.js.map +1 -1
  77. package/dist/canvas/defaultDrawOne.js +11 -6
  78. package/dist/canvas/defaultDrawOne.js.map +1 -1
  79. package/dist/canvas/deps/areaSelect.js +5 -2
  80. package/dist/canvas/deps/areaSelect.js.map +1 -1
  81. package/dist/canvas/deps/booleans.js +3 -2
  82. package/dist/canvas/deps/booleans.js.map +1 -1
  83. package/dist/canvas/deps/enteredGroup.js +81 -0
  84. package/dist/canvas/deps/enteredGroup.js.map +1 -0
  85. package/dist/canvas/deps/hitTestArea.js +28 -16
  86. package/dist/canvas/deps/hitTestArea.js.map +1 -1
  87. package/dist/canvas/deps/insert.js +10 -38
  88. package/dist/canvas/deps/insert.js.map +1 -1
  89. package/dist/canvas/deps/insertSite.js +39 -0
  90. package/dist/canvas/deps/insertSite.js.map +1 -0
  91. package/dist/canvas/deps/lassoSelect.js +6 -3
  92. package/dist/canvas/deps/lassoSelect.js.map +1 -1
  93. package/dist/canvas/deps/pathEditCommits.js +3 -7
  94. package/dist/canvas/deps/pathEditCommits.js.map +1 -1
  95. package/dist/canvas/deps/pathLeaf.js +1 -1
  96. package/dist/canvas/deps/pathLeaf.js.map +1 -1
  97. package/dist/canvas/deps/slice.js +2 -1
  98. package/dist/canvas/deps/slice.js.map +1 -1
  99. package/dist/canvas/derivedPath.js +14 -6
  100. package/dist/canvas/derivedPath.js.map +1 -1
  101. package/dist/canvas/doubleClickTarget.js +9 -11
  102. package/dist/canvas/doubleClickTarget.js.map +1 -1
  103. package/dist/canvas/drawnBounds.js +26 -9
  104. package/dist/canvas/drawnBounds.js.map +1 -1
  105. package/dist/canvas/inheritedPaints.js +55 -0
  106. package/dist/canvas/inheritedPaints.js.map +1 -0
  107. package/dist/canvas/nodeShapes/derivedPainter.js +15 -16
  108. package/dist/canvas/nodeShapes/derivedPainter.js.map +1 -1
  109. package/dist/canvas/nodeShapes/nodePaint.js +7 -34
  110. package/dist/canvas/nodeShapes/nodePaint.js.map +1 -1
  111. package/dist/canvas/nodeShapes/pathPainter.js +7 -7
  112. package/dist/canvas/nodeShapes/pathPainter.js.map +1 -1
  113. package/dist/canvas/nodeShapes/rectFallbackPainter.js +4 -5
  114. package/dist/canvas/nodeShapes/rectFallbackPainter.js.map +1 -1
  115. package/dist/canvas/nodeShapes/shapePainter.js +9 -9
  116. package/dist/canvas/nodeShapes/shapePainter.js.map +1 -1
  117. package/dist/canvas/nodeShapes/textPainter.js +13 -12
  118. package/dist/canvas/nodeShapes/textPainter.js.map +1 -1
  119. package/dist/canvas/ownClip.js +24 -0
  120. package/dist/canvas/ownClip.js.map +1 -0
  121. package/dist/canvas/paintCull.js.map +1 -1
  122. package/dist/canvas/pickIndex/nodeBroadBox.js +86 -0
  123. package/dist/canvas/pickIndex/nodeBroadBox.js.map +1 -0
  124. package/dist/canvas/pickIndex/scenePickIndex.js +208 -0
  125. package/dist/canvas/pickIndex/scenePickIndex.js.map +1 -0
  126. package/dist/canvas/pickReach.js +3 -3
  127. package/dist/canvas/pickReach.js.map +1 -1
  128. package/dist/canvas/pickWalk.js +17 -91
  129. package/dist/canvas/pickWalk.js.map +1 -1
  130. package/dist/canvas/poseCascade.js +1 -1
  131. package/dist/canvas/poseCascade.js.map +1 -1
  132. package/dist/canvas/publishPreviews.js +97 -0
  133. package/dist/canvas/publishPreviews.js.map +1 -0
  134. package/dist/canvas/renderSceneToPixels.js +1 -1
  135. package/dist/canvas/renderSceneToPixels.js.map +1 -1
  136. package/dist/canvas/sceneAdapter.js +7 -5
  137. package/dist/canvas/sceneAdapter.js.map +1 -1
  138. package/dist/canvas/sceneClipboard.js +17 -10
  139. package/dist/canvas/sceneClipboard.js.map +1 -1
  140. package/dist/canvas/scenePickReads.js +37 -0
  141. package/dist/canvas/scenePickReads.js.map +1 -0
  142. package/dist/canvas/scenePickSource.js +74 -0
  143. package/dist/canvas/scenePickSource.js.map +1 -0
  144. package/dist/canvas/sceneSlotWiring.js +9 -3
  145. package/dist/canvas/sceneSlotWiring.js.map +1 -1
  146. package/dist/canvas/sceneViewRender.js +9 -4
  147. package/dist/canvas/sceneViewRender.js.map +1 -1
  148. package/dist/canvas/shownNodes.js +15 -0
  149. package/dist/canvas/shownNodes.js.map +1 -0
  150. package/dist/canvas/surfaceContribution.js +12 -8
  151. package/dist/canvas/surfaceContribution.js.map +1 -1
  152. package/dist/canvas/useCanvasView.js +4 -2
  153. package/dist/canvas/useCanvasView.js.map +1 -1
  154. package/dist/canvas/useLayerStack.js +6 -2
  155. package/dist/canvas/useLayerStack.js.map +1 -1
  156. package/dist/canvas/useSceneAdapter.js +5 -3
  157. package/dist/canvas/useSceneAdapter.js.map +1 -1
  158. package/dist/canvas/useViewAim.js +121 -0
  159. package/dist/canvas/useViewAim.js.map +1 -0
  160. package/dist/canvas/useViewNesting.js +3 -2
  161. package/dist/canvas/useViewNesting.js.map +1 -1
  162. package/dist/canvas/useViewRegistrySurface.js +4 -2
  163. package/dist/canvas/useViewRegistrySurface.js.map +1 -1
  164. package/dist/canvas/viewMarkers.js +63 -0
  165. package/dist/canvas/viewMarkers.js.map +1 -0
  166. package/dist/canvas/viewRegistry.js +27 -1
  167. package/dist/canvas/viewRegistry.js.map +1 -1
  168. package/dist/clipboard.d.ts +2 -2
  169. package/dist/{clone-C3e0OTuF.d.ts → clone-qb2e1F5p.d.ts} +2 -2
  170. package/dist/clone.d.ts +3 -3
  171. package/dist/core/isPlainObject.js +2 -2
  172. package/dist/core/layers/layerGroup.js.map +1 -1
  173. package/dist/core/pages/pageEdits.js +2 -3
  174. package/dist/core/pages/pageEdits.js.map +1 -1
  175. package/dist/core/paint/meshKindLazy.js +59 -2
  176. package/dist/core/paint/meshKindLazy.js.map +1 -1
  177. package/dist/core/scene/NodeRouting.js.map +1 -1
  178. package/dist/core/scene/arrivalWindow.js +1 -1
  179. package/dist/core/scene/arrivalWindow.js.map +1 -1
  180. package/dist/core/scene/clipNothing.js +10 -0
  181. package/dist/core/scene/clipNothing.js.map +1 -0
  182. package/dist/core/scene/declaredFieldSetters.js +44 -0
  183. package/dist/core/scene/declaredFieldSetters.js.map +1 -0
  184. package/dist/core/scene/depMemo.js +14 -3
  185. package/dist/core/scene/depMemo.js.map +1 -1
  186. package/dist/core/scene/dependents.js +9 -1
  187. package/dist/core/scene/dependents.js.map +1 -1
  188. package/dist/core/scene/derivedParts.js +10 -11
  189. package/dist/core/scene/derivedParts.js.map +1 -1
  190. package/dist/core/scene/documentOf.js +43 -0
  191. package/dist/core/scene/documentOf.js.map +1 -0
  192. package/dist/core/scene/effectivePose.js +44 -15
  193. package/dist/core/scene/effectivePose.js.map +1 -1
  194. package/dist/core/scene/fieldEdits.js +17 -14
  195. package/dist/core/scene/fieldEdits.js.map +1 -1
  196. package/dist/core/scene/fontReads.js +37 -0
  197. package/dist/core/scene/fontReads.js.map +1 -0
  198. package/dist/core/scene/historyForm.js +4 -4
  199. package/dist/core/scene/historyForm.js.map +1 -1
  200. package/dist/core/scene/inheritedPaint.js +97 -0
  201. package/dist/core/scene/inheritedPaint.js.map +1 -0
  202. package/dist/core/scene/kitOps.js +3 -23
  203. package/dist/core/scene/kitOps.js.map +1 -1
  204. package/dist/core/scene/kitRegistry.js +5 -0
  205. package/dist/core/scene/kitRegistry.js.map +1 -1
  206. package/dist/core/scene/layoutPass.js +1 -2
  207. package/dist/core/scene/layoutPass.js.map +1 -1
  208. package/dist/core/scene/nodeAsShown.js +72 -0
  209. package/dist/core/scene/nodeAsShown.js.map +1 -0
  210. package/dist/core/scene/nodeFnFields.js +2 -10
  211. package/dist/core/scene/nodeFnFields.js.map +1 -1
  212. package/dist/core/scene/nodeMemo.js +21 -8
  213. package/dist/core/scene/nodeMemo.js.map +1 -1
  214. package/dist/core/scene/nodeStore.js +2 -4
  215. package/dist/core/scene/nodeStore.js.map +1 -1
  216. package/dist/core/scene/pathEffects/blend.js.map +1 -1
  217. package/dist/core/scene/pathEffects/derive.js +10 -4
  218. package/dist/core/scene/pathEffects/derive.js.map +1 -1
  219. package/dist/core/scene/pathEffects/effects.js +3 -1
  220. package/dist/core/scene/pathEffects/effects.js.map +1 -1
  221. package/dist/core/scene/pathEffects/foundHidden.js +35 -0
  222. package/dist/core/scene/pathEffects/foundHidden.js.map +1 -0
  223. package/dist/core/scene/pathEffects/textAlong.js +95 -0
  224. package/dist/core/scene/pathEffects/textAlong.js.map +1 -0
  225. package/dist/core/scene/plyStacks.js +89 -0
  226. package/dist/core/scene/plyStacks.js.map +1 -0
  227. package/dist/core/scene/poseHold.js +42 -24
  228. package/dist/core/scene/poseHold.js.map +1 -1
  229. package/dist/core/scene/poseOverrides.js +35 -38
  230. package/dist/core/scene/poseOverrides.js.map +1 -1
  231. package/dist/core/scene/posePlies.js +59 -0
  232. package/dist/core/scene/posePlies.js.map +1 -0
  233. package/dist/core/scene/reconcileSpecs.js +6 -15
  234. package/dist/core/scene/reconcileSpecs.js.map +1 -1
  235. package/dist/core/scene/renderOrder.js +10 -4
  236. package/dist/core/scene/renderOrder.js.map +1 -1
  237. package/dist/core/scene/sameValue.js +17 -0
  238. package/dist/core/scene/sameValue.js.map +1 -0
  239. package/dist/core/scene/scene.js +3 -3
  240. package/dist/core/scene/scene.js.map +1 -1
  241. package/dist/core/scene/sceneEdits.js +8 -0
  242. package/dist/core/scene/sceneEdits.js.map +1 -1
  243. package/dist/core/scene/sceneState.js +1 -2
  244. package/dist/core/scene/sceneState.js.map +1 -1
  245. package/dist/core/scene/serialization.js +45 -9
  246. package/dist/core/scene/serialization.js.map +1 -1
  247. package/dist/core/scene/staleReplay.js +5 -2
  248. package/dist/core/scene/staleReplay.js.map +1 -1
  249. package/dist/core/scene/statedFields.js +4 -2
  250. package/dist/core/scene/statedFields.js.map +1 -1
  251. package/dist/core/scene/treeEdits.js +2 -4
  252. package/dist/core/scene/treeEdits.js.map +1 -1
  253. package/dist/core/scene/treeOrder.js +3 -1
  254. package/dist/core/scene/treeOrder.js.map +1 -1
  255. package/dist/core/scene/treeReads.js +1 -2
  256. package/dist/core/scene/treeReads.js.map +1 -1
  257. package/dist/core/scene/treeShape.js +13 -0
  258. package/dist/core/scene/treeShape.js.map +1 -0
  259. package/dist/core/scene/types.js.map +1 -1
  260. package/dist/core/scene/useScene.js +1 -1
  261. package/dist/core/scene/useScene.js.map +1 -1
  262. package/dist/{cornerHandles-BHuoMs1o.d.ts → cornerHandles-CNCb7aTY.d.ts} +3 -2
  263. package/dist/{depSchema-BpZNOv7q.d.ts → depSchema-B1RS-IJx.d.ts} +39 -18
  264. package/dist/devtools/handlers.js +1 -1
  265. package/dist/devtools/handlers.js.map +1 -1
  266. package/dist/devtools/protocol.js.map +1 -1
  267. package/dist/devtools/registry.js +4 -4
  268. package/dist/devtools/registry.js.map +1 -1
  269. package/dist/devtools-protocol.d.ts +4 -3
  270. package/dist/devtools.d.ts +3 -2
  271. package/dist/features/measure/measureContribution.js +4 -2
  272. package/dist/features/measure/measureContribution.js.map +1 -1
  273. package/dist/features/measure/measureHit.js +5 -3
  274. package/dist/features/measure/measureHit.js.map +1 -1
  275. package/dist/features/measure/measurement.js +1 -1
  276. package/dist/features/measure/measurement.js.map +1 -1
  277. package/dist/features/modes/modeLayers.js +14 -7
  278. package/dist/features/modes/modeLayers.js.map +1 -1
  279. package/dist/features/modes/modeTriggers.js +10 -6
  280. package/dist/features/modes/modeTriggers.js.map +1 -1
  281. package/dist/features/pathEffects/effectSources.js +69 -0
  282. package/dist/features/pathEffects/effectSources.js.map +1 -0
  283. package/dist/features/pathEffects/readSource.js +18 -2
  284. package/dist/features/pathEffects/readSource.js.map +1 -1
  285. package/dist/features/pathEffects/textItems.js +53 -0
  286. package/dist/features/pathEffects/textItems.js.map +1 -0
  287. package/dist/features/pathEffects/useEffectSourcesLayer.js +53 -0
  288. package/dist/features/pathEffects/useEffectSourcesLayer.js.map +1 -0
  289. package/dist/features/paths/editablePath.js +1 -1
  290. package/dist/features/paths/editablePath.js.map +1 -1
  291. package/dist/features/paths/pathEditState.js +5 -2
  292. package/dist/features/paths/pathEditState.js.map +1 -1
  293. package/dist/features/paths/pathSnap/sceneIndex.js +1 -1
  294. package/dist/features/paths/pathSnap/sceneIndex.js.map +1 -1
  295. package/dist/features/selection/enteredGroupFrame.js +65 -0
  296. package/dist/features/selection/enteredGroupFrame.js.map +1 -0
  297. package/dist/features/selection/enteredGroupScope.js +44 -0
  298. package/dist/features/selection/enteredGroupScope.js.map +1 -0
  299. package/dist/features/text/sceneTextDrafts.js +64 -0
  300. package/dist/features/text/sceneTextDrafts.js.map +1 -0
  301. package/dist/features/text/textHitAt.js +34 -3
  302. package/dist/features/text/textHitAt.js.map +1 -1
  303. package/dist/features/text/useSceneTextEdit.js +23 -19
  304. package/dist/features/text/useSceneTextEdit.js.map +1 -1
  305. package/dist/features/viewports/aim.js +105 -0
  306. package/dist/features/viewports/aim.js.map +1 -0
  307. package/dist/features/viewports/viewMarker.js +82 -0
  308. package/dist/features/viewports/viewMarker.js.map +1 -0
  309. package/dist/features/viewports/viewMarkerDrag.js +55 -0
  310. package/dist/features/viewports/viewMarkerDrag.js.map +1 -0
  311. package/dist/index.d.ts +709 -258
  312. package/dist/index.js +33 -12
  313. package/dist/interactions/actions/admitsChild.js +11 -0
  314. package/dist/interactions/actions/admitsChild.js.map +1 -0
  315. package/dist/interactions/actions/booleans/booleans.js +2 -1
  316. package/dist/interactions/actions/booleans/booleans.js.map +1 -1
  317. package/dist/interactions/actions/booleans/operands.js +6 -5
  318. package/dist/interactions/actions/booleans/operands.js.map +1 -1
  319. package/dist/interactions/actions/clipboard/action.js +27 -17
  320. package/dist/interactions/actions/clipboard/action.js.map +1 -1
  321. package/dist/interactions/actions/defaults/anchorEditing.js +44 -23
  322. package/dist/interactions/actions/defaults/anchorEditing.js.map +1 -1
  323. package/dist/interactions/actions/defaults/anchorJoin.js +12 -6
  324. package/dist/interactions/actions/defaults/anchorJoin.js.map +1 -1
  325. package/dist/interactions/actions/defaults/bendSegment.js +7 -4
  326. package/dist/interactions/actions/defaults/bendSegment.js.map +1 -1
  327. package/dist/interactions/actions/defaults/cancelGesture.js +11 -8
  328. package/dist/interactions/actions/defaults/cancelGesture.js.map +1 -1
  329. package/dist/interactions/actions/defaults/contextMenu.js +33 -11
  330. package/dist/interactions/actions/defaults/contextMenu.js.map +1 -1
  331. package/dist/interactions/actions/defaults/createPaintAction.js +5 -2
  332. package/dist/interactions/actions/defaults/createPaintAction.js.map +1 -1
  333. package/dist/interactions/actions/defaults/delete.js +28 -14
  334. package/dist/interactions/actions/defaults/delete.js.map +1 -1
  335. package/dist/interactions/actions/defaults/duplicate.js +11 -8
  336. package/dist/interactions/actions/defaults/duplicate.js.map +1 -1
  337. package/dist/interactions/actions/defaults/enterGroup.js +88 -0
  338. package/dist/interactions/actions/defaults/enterGroup.js.map +1 -0
  339. package/dist/interactions/actions/defaults/enterPathEdit.js +20 -10
  340. package/dist/interactions/actions/defaults/enterPathEdit.js.map +1 -1
  341. package/dist/interactions/actions/defaults/enterTextEdit.js +1 -1
  342. package/dist/interactions/actions/defaults/enterTextEdit.js.map +1 -1
  343. package/dist/interactions/actions/defaults/escape.js +11 -8
  344. package/dist/interactions/actions/defaults/escape.js.map +1 -1
  345. package/dist/interactions/actions/defaults/exitPathEdit.js +7 -4
  346. package/dist/interactions/actions/defaults/exitPathEdit.js.map +1 -1
  347. package/dist/interactions/actions/defaults/group.js +26 -20
  348. package/dist/interactions/actions/defaults/group.js.map +1 -1
  349. package/dist/interactions/actions/defaults/ingest.js +10 -4
  350. package/dist/interactions/actions/defaults/ingest.js.map +1 -1
  351. package/dist/interactions/actions/defaults/insertPathAnchor.js +7 -4
  352. package/dist/interactions/actions/defaults/insertPathAnchor.js.map +1 -1
  353. package/dist/interactions/actions/defaults/nudge.js +8 -2
  354. package/dist/interactions/actions/defaults/nudge.js.map +1 -1
  355. package/dist/interactions/actions/defaults/pathEditTools.js +11 -8
  356. package/dist/interactions/actions/defaults/pathEditTools.js.map +1 -1
  357. package/dist/interactions/actions/defaults/pinchZoom.js +7 -4
  358. package/dist/interactions/actions/defaults/pinchZoom.js.map +1 -1
  359. package/dist/interactions/actions/defaults/reorder.js +24 -6
  360. package/dist/interactions/actions/defaults/reorder.js.map +1 -1
  361. package/dist/interactions/actions/defaults/selectAll.js +15 -8
  362. package/dist/interactions/actions/defaults/selectAll.js.map +1 -1
  363. package/dist/interactions/actions/defaults/selectDeep.js +35 -0
  364. package/dist/interactions/actions/defaults/selectDeep.js.map +1 -0
  365. package/dist/interactions/actions/defaults/setFill.js +7 -3
  366. package/dist/interactions/actions/defaults/setFill.js.map +1 -1
  367. package/dist/interactions/actions/defaults/setFillOpacity.js +1 -1
  368. package/dist/interactions/actions/defaults/setStroke.js +12 -11
  369. package/dist/interactions/actions/defaults/setStroke.js.map +1 -1
  370. package/dist/interactions/actions/defaults/setStrokeOpacity.js +1 -1
  371. package/dist/interactions/actions/defaults/toolActivate.js +7 -1
  372. package/dist/interactions/actions/defaults/toolActivate.js.map +1 -1
  373. package/dist/interactions/actions/defaults/toolResetToDefault.js +7 -4
  374. package/dist/interactions/actions/defaults/toolResetToDefault.js.map +1 -1
  375. package/dist/interactions/actions/defaults/undoRedo.js +19 -13
  376. package/dist/interactions/actions/defaults/undoRedo.js.map +1 -1
  377. package/dist/interactions/actions/defaults/viewportWheelPan.js +16 -7
  378. package/dist/interactions/actions/defaults/viewportWheelPan.js.map +1 -1
  379. package/dist/interactions/actions/defaults/viewportZoom.js +24 -6
  380. package/dist/interactions/actions/defaults/viewportZoom.js.map +1 -1
  381. package/dist/interactions/actions/drawnBoxes.js +2 -1
  382. package/dist/interactions/actions/drawnBoxes.js.map +1 -1
  383. package/dist/interactions/actions/edit-anchors/action.js +7 -4
  384. package/dist/interactions/actions/edit-anchors/action.js.map +1 -1
  385. package/dist/interactions/actions/flip/action.js +8 -2
  386. package/dist/interactions/actions/flip/action.js.map +1 -1
  387. package/dist/interactions/actions/insert/action.js +1 -0
  388. package/dist/interactions/actions/insert/action.js.map +1 -1
  389. package/dist/interactions/actions/insert/parent.js +7 -5
  390. package/dist/interactions/actions/insert/parent.js.map +1 -1
  391. package/dist/interactions/actions/insert/placeAction.js +3 -2
  392. package/dist/interactions/actions/insert/placeAction.js.map +1 -1
  393. package/dist/interactions/actions/insert/repositionAction.js +2 -1
  394. package/dist/interactions/actions/insert/repositionAction.js.map +1 -1
  395. package/dist/interactions/actions/insert/session.js +2 -2
  396. package/dist/interactions/actions/insert/session.js.map +1 -1
  397. package/dist/interactions/actions/move/action.js +7 -4
  398. package/dist/interactions/actions/move/action.js.map +1 -1
  399. package/dist/interactions/actions/move/commit/reparent.js +1 -1
  400. package/dist/interactions/actions/move/commit/reparent.js.map +1 -1
  401. package/dist/interactions/actions/move/gestureAdapter.js +6 -7
  402. package/dist/interactions/actions/move/gestureAdapter.js.map +1 -1
  403. package/dist/interactions/actions/move/layout/exits.js +1 -1
  404. package/dist/interactions/actions/move/layout/exits.js.map +1 -1
  405. package/dist/interactions/actions/move/session.js +4 -4
  406. package/dist/interactions/actions/move/session.js.map +1 -1
  407. package/dist/interactions/actions/outlines/createOutlinesAction.js +8 -5
  408. package/dist/interactions/actions/outlines/createOutlinesAction.js.map +1 -1
  409. package/dist/interactions/actions/outlines/outlineStroke.js +5 -3
  410. package/dist/interactions/actions/outlines/outlineStroke.js.map +1 -1
  411. package/dist/interactions/actions/pathCommands/cutJoin.js +8 -5
  412. package/dist/interactions/actions/pathCommands/cutJoin.js.map +1 -1
  413. package/dist/interactions/actions/pathCommands/pathNodes.js +14 -5
  414. package/dist/interactions/actions/pathCommands/pathNodes.js.map +1 -1
  415. package/dist/interactions/actions/resize/cornerHandles.js +2 -1
  416. package/dist/interactions/actions/resize/cornerHandles.js.map +1 -1
  417. package/dist/interactions/actions/selectionSubtree.js +12 -7
  418. package/dist/interactions/actions/selectionSubtree.js.map +1 -1
  419. package/dist/interactions/actions/transform-again/action.js +8 -5
  420. package/dist/interactions/actions/transform-again/action.js.map +1 -1
  421. package/dist/interactions/gestures/thresholdDrag/thresholdDrag.js +14 -2
  422. package/dist/interactions/gestures/thresholdDrag/thresholdDrag.js.map +1 -1
  423. package/dist/json.d.ts +4 -0
  424. package/dist/json.js +3 -0
  425. package/dist/kitSettingsSchema.js +8 -1
  426. package/dist/kitSettingsSchema.js.map +1 -1
  427. package/dist/{math-CrJULaZI.d.ts → math-C_elShP_.d.ts} +7 -1
  428. package/dist/math.d.ts +1 -1
  429. package/dist/math.js +2 -1
  430. package/dist/move.d.ts +4 -4
  431. package/dist/{options-DBxEryYq.d.ts → options-ClEm3SEl.d.ts} +1 -1
  432. package/dist/resize.d.ts +4 -4
  433. package/dist/test-seams.d.ts +6 -6
  434. package/dist/tools/builtin/ellipse/useEllipseTool.js +1 -0
  435. package/dist/tools/builtin/ellipse/useEllipseTool.js.map +1 -1
  436. package/dist/tools/builtin/eyedropper/useEyedropperTool.js +2 -1
  437. package/dist/tools/builtin/eyedropper/useEyedropperTool.js.map +1 -1
  438. package/dist/tools/builtin/hand/dragPanContribution.js +4 -1
  439. package/dist/tools/builtin/hand/dragPanContribution.js.map +1 -1
  440. package/dist/tools/builtin/hand/useHandTool.js +7 -4
  441. package/dist/tools/builtin/hand/useHandTool.js.map +1 -1
  442. package/dist/tools/builtin/image/useImageTool.js +1 -0
  443. package/dist/tools/builtin/image/useImageTool.js.map +1 -1
  444. package/dist/tools/builtin/lasso/useLassoTool.js +1 -0
  445. package/dist/tools/builtin/lasso/useLassoTool.js.map +1 -1
  446. package/dist/tools/builtin/line/useLineTool.js +1 -0
  447. package/dist/tools/builtin/line/useLineTool.js.map +1 -1
  448. package/dist/tools/builtin/measure/useMeasureTool.js +12 -5
  449. package/dist/tools/builtin/measure/useMeasureTool.js.map +1 -1
  450. package/dist/tools/builtin/pen/usePenTool.js +14 -6
  451. package/dist/tools/builtin/pen/usePenTool.js.map +1 -1
  452. package/dist/tools/builtin/pencil/usePencilTool.js +1 -0
  453. package/dist/tools/builtin/pencil/usePencilTool.js.map +1 -1
  454. package/dist/tools/builtin/polygon/usePolygonTool.js +13 -4
  455. package/dist/tools/builtin/polygon/usePolygonTool.js.map +1 -1
  456. package/dist/tools/builtin/pressTarget.js +22 -0
  457. package/dist/tools/builtin/pressTarget.js.map +1 -0
  458. package/dist/tools/builtin/rect/useRectTool.js +1 -0
  459. package/dist/tools/builtin/rect/useRectTool.js.map +1 -1
  460. package/dist/tools/builtin/select/adapterPointQuery.js +6 -5
  461. package/dist/tools/builtin/select/adapterPointQuery.js.map +1 -1
  462. package/dist/tools/builtin/select/collapseDeferred.js +40 -0
  463. package/dist/tools/builtin/select/collapseDeferred.js.map +1 -0
  464. package/dist/tools/builtin/select/groupEntry.js +82 -0
  465. package/dist/tools/builtin/select/groupEntry.js.map +1 -0
  466. package/dist/tools/builtin/select/pressDecision.js +32 -0
  467. package/dist/tools/builtin/select/pressDecision.js.map +1 -0
  468. package/dist/tools/builtin/select/selectionContributions.js +22 -13
  469. package/dist/tools/builtin/select/selectionContributions.js.map +1 -1
  470. package/dist/tools/builtin/select/useSelectTool.js +74 -55
  471. package/dist/tools/builtin/select/useSelectTool.js.map +1 -1
  472. package/dist/tools/builtin/slice/useSliceTool.js +22 -8
  473. package/dist/tools/builtin/slice/useSliceTool.js.map +1 -1
  474. package/dist/tools/builtin/star/useStarTool.js +13 -4
  475. package/dist/tools/builtin/star/useStarTool.js.map +1 -1
  476. package/dist/tools/builtin/sticky/stickyNode.js +4 -1
  477. package/dist/tools/builtin/sticky/stickyNode.js.map +1 -1
  478. package/dist/tools/builtin/sticky/useStickyTool.js +10 -5
  479. package/dist/tools/builtin/sticky/useStickyTool.js.map +1 -1
  480. package/dist/tools/builtin/text/useTextTool.js +3 -1
  481. package/dist/tools/builtin/text/useTextTool.js.map +1 -1
  482. package/dist/{types-7puAuVD2.d.ts → types-49uYJN3j.d.ts} +1 -1
  483. package/dist/{types-CniVctmk.d.ts → types-BEdRIhNc.d.ts} +272 -109
  484. package/dist/{types-oFeQ5VjV.d.ts → types-p2alu-R1.d.ts} +1 -1
  485. package/dist/util/paint.js +1 -3
  486. package/dist/util/paint.js.map +1 -1
  487. package/dist/version.js +1 -1
  488. package/package.json +29 -25
@@ -5,6 +5,7 @@ import { visualBoundsViaDescriptor } from "../../../core/geometry/poseDescriptor
5
5
  import { asNodeId } from "../../../core/scene/types.js";
6
6
  import { scenePoseFrame } from "../poseFrame.js";
7
7
  import { nodeDescriptors, poseDescriptorOf } from "../poseDescriptorDep.js";
8
+ import { pressTarget } from "../../../tools/builtin/pressTarget.js";
8
9
  import { ActionDisabledReason } from "@weasel-js/routing";
9
10
 
10
11
  //#region src/interactions/actions/defaults/contextMenu.ts
@@ -41,12 +42,13 @@ function menuHitFor(deps, at) {
41
42
  const hit = deps.hitAt?.(at);
42
43
  if (!hit) return { hit: {} };
43
44
  if (hit.bodyTarget === "empty") return { hit: { bodyTarget: "empty" } };
45
+ const target = hit.bodyTarget === "unselected-body" && hit.id !== void 0 ? groupFor(deps, hit.id) : void 0;
44
46
  return {
45
47
  hit: {
46
48
  bodyTarget: "selected-body",
47
- bodyKind: hit.bodyKind
49
+ bodyKind: (target !== void 0 ? deps.kindOfNode?.(target) : void 0) ?? hit.bodyKind
48
50
  },
49
- ...hit.bodyTarget === "unselected-body" && hit.id !== void 0 ? { select: hit.id } : {}
51
+ ...target !== void 0 ? { select: target } : {}
50
52
  };
51
53
  }
52
54
  if (!deps.selection) return { hit: {} };
@@ -56,6 +58,16 @@ function menuHitFor(deps, at) {
56
58
  bodyKind: ids.length === 1 ? deps.kindOfNode?.(ids[0]) : void 0
57
59
  } };
58
60
  }
61
+ /** The node a right-click selects: the press target for `id`, as a left press would pick. */
62
+ function groupFor(deps, id) {
63
+ const scene = deps.scene;
64
+ if (!scene) return id;
65
+ const node = (n) => scene.get(asNodeId(n));
66
+ return pressTarget({
67
+ getParent: (n) => node(n)?.parent ?? null,
68
+ getNode: node
69
+ }, id, deps.enteredGroup?.get() ?? null);
70
+ }
59
71
  /**
60
72
  * Open the menu for a right-click, or for Shift+F10 when `params` carry no client point. Reads
61
73
  * only `menuHost`, `view` and `worldToClient` on a surface without a scene; `selection`, `scene`,
@@ -105,17 +117,26 @@ var contextMenuAction = {
105
117
  id: "menu.context",
106
118
  label: "Show Context Menu",
107
119
  defaultBinding: [
108
- { kind: "contextMenu" },
109
120
  {
110
- kind: "key",
111
- key: "F10",
112
- mods: { shift: true },
113
- phase: [...INITIAL]
121
+ spec: { kind: "contextMenu" },
122
+ opts: { id: "menu.context.contextMenu" }
114
123
  },
115
124
  {
116
- kind: "key",
117
- key: "ContextMenu",
118
- phase: [...INITIAL]
125
+ spec: {
126
+ kind: "key",
127
+ key: "F10",
128
+ mods: { shift: true },
129
+ phase: [...INITIAL]
130
+ },
131
+ opts: { id: "menu.context.key" }
132
+ },
133
+ {
134
+ spec: {
135
+ kind: "key",
136
+ key: "ContextMenu",
137
+ phase: [...INITIAL]
138
+ },
139
+ opts: { id: "menu.context.menuKey" }
119
140
  }
120
141
  ],
121
142
  requires: [
@@ -126,7 +147,8 @@ var contextMenuAction = {
126
147
  "view",
127
148
  "worldToClient",
128
149
  "hitAt",
129
- "kindOfNode"
150
+ "kindOfNode",
151
+ "enteredGroup"
130
152
  ],
131
153
  enabled: (deps, at) => deps?.menuHost?.has({
132
154
  hit: menuHitFor(deps, at).hit,
@@ -1 +1 @@
1
- {"version":3,"file":"contextMenu.js","names":[],"sources":["../../../../src/interactions/actions/defaults/contextMenu.ts"],"sourcesContent":["import { ActionDisabledReason, type Action, type ActionDeps, type MenuHit } from '@weasel-js/routing';\nimport { scenePoseFrame } from '../poseFrame';\nimport { nodeDescriptors, poseDescriptorOf } from '../poseDescriptorDep';\nimport { visualBoundsViaDescriptor } from '../resize/geometry';\nimport { unionAABB } from 'core/geometry/unionBounds';\nimport { screenToWorld } from 'core/viewport/viewTransform';\nimport { viewToTransform } from 'core/viewport/view';\nimport { asNodeId } from 'core/scene/types';\nimport type { Point } from '@weasel-js/geom';\n\n/** World center of the selection's bounds, else of the visible canvas. */\nexport function keyboardAnchor(deps: ActionDeps): Point | null {\n const ids = deps.selection?.get() ?? [];\n if (ids.length && deps.scene) {\n const frame = scenePoseFrame(deps.scene);\n const descriptorOf = nodeDescriptors(deps.scene, poseDescriptorOf(deps.poseDescriptor));\n const box = unionAABB(ids.map((id) => visualBoundsViaDescriptor(frame.world(id), descriptorOf(id))));\n if (box) return { x: box.x + box.width / 2, y: box.y + box.height / 2 };\n }\n const view = deps.view?.get();\n const size = deps.view?.hostSize?.();\n if (!view || !size) return null;\n const [x, y] = screenToWorld(size.width / 2, size.height / 2, viewToTransform(view));\n return { x, y };\n}\n\n/**\n * The hit a menu is picked for, from the dispatcher's own classifier (the\n * `hitAt` and `kindOfNode` deps). A shape under `at` counts as selected, since\n * opening selects it first, and `select` names it when it is not yet; with no\n * `at`, the current selection. Without a classifier wired, a pointer hit names\n * no body at all, and without a selection neither does a keyboard one.\n */\nexport function menuHitFor(deps: ActionDeps, at?: Point): { hit: MenuHit; select?: string } {\n if (at) {\n const hit = deps.hitAt?.(at);\n if (!hit) return { hit: {} };\n if (hit.bodyTarget === 'empty') return { hit: { bodyTarget: 'empty' } };\n return {\n hit: { bodyTarget: 'selected-body', bodyKind: hit.bodyKind },\n ...(hit.bodyTarget === 'unselected-body' && hit.id !== undefined ? { select: hit.id } : {}),\n };\n }\n if (!deps.selection) return { hit: {} };\n const ids = deps.selection.get();\n return { hit: { bodyTarget: ids.length ? 'selected-body' : 'empty', bodyKind: ids.length === 1 ? deps.kindOfNode?.(ids[0]!) : undefined } };\n}\n\n/**\n * Open the menu for a right-click, or for Shift+F10 when `params` carry no client point. Reads\n * only `menuHost`, `view` and `worldToClient` on a surface without a scene; `selection`, `scene`,\n * `hitAt` and `kindOfNode` refine the hit and the keyboard anchor where they are supplied.\n */\nexport function openContextMenu(\n deps: ActionDeps,\n params?: Record<string, unknown>,\n anchorOf: (deps: ActionDeps) => Point | null = keyboardAnchor,\n): boolean {\n const host = deps.menuHost;\n if (!host) return false;\n const p = params ?? {};\n if (typeof p.clientX === 'number' && typeof p.worldX === 'number') {\n const world = { x: p.worldX, y: p.worldY as number };\n const { hit, select } = menuHitFor(deps, world);\n if (select) deps.selection?.set([asNodeId(select)]);\n return host.open({\n hit,\n client: { x: p.clientX, y: p.clientY as number }, world, source: 'pointer',\n });\n }\n const world = anchorOf(deps);\n const client = world && deps.worldToClient?.(world.x, world.y);\n if (!world || !client) return false;\n return host.open({ hit: menuHitFor(deps).hit, client, world, source: 'keyboard' });\n}\n\nconst INITIAL = [{ channel: '*', phase: 'initial' }] as const;\n\n/**\n * Opens the context menu: for the pointer on a right-click or an unclaimed\n * long-press, selecting the shape under it first; for the keyboard on\n * Shift+F10 or the ContextMenu key, at the selection or else the middle of the view.\n */\nexport const contextMenuAction: Action & { requires: string[] } = {\n id: 'menu.context',\n label: 'Show Context Menu',\n defaultBinding: [\n { kind: 'contextMenu' },\n { kind: 'key', key: 'F10', mods: { shift: true }, phase: [...INITIAL] },\n { kind: 'key', key: 'ContextMenu', phase: [...INITIAL] },\n ],\n requires: ['menuHost', 'selection', 'scene', 'poseDescriptor', 'view', 'worldToClient', 'hitAt', 'kindOfNode'],\n // Disabled when no menu would open, so the dispatcher leaves the press, click and drag to whatever else is bound.\n enabled: (deps, at) => (deps?.menuHost?.has({ hit: menuHitFor(deps, at).hit, client: { x: 0, y: 0 }, world: at })\n ? true\n : ActionDisabledReason.NotApplicable),\n invoker: { timing: 'immediate', run: (deps, params) => { openContextMenu(deps, params); } },\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"contextMenu.js","names":[],"sources":["../../../../src/interactions/actions/defaults/contextMenu.ts"],"sourcesContent":["import { ActionDisabledReason, type Action, type ActionDeps, type MenuHit } from '@weasel-js/routing';\nimport { scenePoseFrame } from '../poseFrame';\nimport { nodeDescriptors, poseDescriptorOf } from '../poseDescriptorDep';\nimport { visualBoundsViaDescriptor } from '../resize/geometry';\nimport { unionAABB } from 'core/geometry/unionBounds';\nimport { screenToWorld } from 'core/viewport/viewTransform';\nimport { viewToTransform } from 'core/viewport/view';\nimport { asNodeId } from 'core/scene/types';\nimport type { Point } from '@weasel-js/geom';\nimport { pressTarget } from 'tools/builtin/pressTarget';\n\n/** World center of the selection's bounds, else of the visible canvas. */\nexport function keyboardAnchor(deps: ActionDeps): Point | null {\n const ids = deps.selection?.get() ?? [];\n if (ids.length && deps.scene) {\n const frame = scenePoseFrame(deps.scene);\n const descriptorOf = nodeDescriptors(deps.scene, poseDescriptorOf(deps.poseDescriptor));\n const box = unionAABB(ids.map((id) => visualBoundsViaDescriptor(frame.world(id), descriptorOf(id))));\n if (box) return { x: box.x + box.width / 2, y: box.y + box.height / 2 };\n }\n const view = deps.view?.get();\n const size = deps.view?.hostSize?.();\n if (!view || !size) return null;\n const [x, y] = screenToWorld(size.width / 2, size.height / 2, viewToTransform(view));\n return { x, y };\n}\n\n/**\n * The hit a menu is picked for, from the dispatcher's own classifier (the\n * `hitAt` and `kindOfNode` deps). A shape under `at` counts as selected, since\n * opening selects it first, and `select` names it when it is not yet; with no\n * `at`, the current selection. Without a classifier wired, a pointer hit names\n * no body at all, and without a selection neither does a keyboard one.\n */\nexport function menuHitFor(deps: ActionDeps, at?: Point): { hit: MenuHit; select?: string } {\n if (at) {\n const hit = deps.hitAt?.(at);\n if (!hit) return { hit: {} };\n if (hit.bodyTarget === 'empty') return { hit: { bodyTarget: 'empty' } };\n const target = hit.bodyTarget === 'unselected-body' && hit.id !== undefined ? groupFor(deps, hit.id) : undefined;\n const bodyKind = (target !== undefined ? deps.kindOfNode?.(target) : undefined) ?? hit.bodyKind;\n return { hit: { bodyTarget: 'selected-body', bodyKind }, ...(target !== undefined ? { select: target } : {}) };\n }\n if (!deps.selection) return { hit: {} };\n const ids = deps.selection.get();\n return { hit: { bodyTarget: ids.length ? 'selected-body' : 'empty', bodyKind: ids.length === 1 ? deps.kindOfNode?.(ids[0]!) : undefined } };\n}\n\n/** The node a right-click selects: the press target for `id`, as a left press would pick. */\nfunction groupFor(deps: ActionDeps, id: string): string {\n const scene = deps.scene;\n if (!scene) return id;\n const node = (n: string) => scene.get(asNodeId(n));\n return pressTarget(\n { getParent: (n) => node(n)?.parent ?? null, getNode: node },\n id,\n deps.enteredGroup?.get() ?? null,\n );\n}\n\n/**\n * Open the menu for a right-click, or for Shift+F10 when `params` carry no client point. Reads\n * only `menuHost`, `view` and `worldToClient` on a surface without a scene; `selection`, `scene`,\n * `hitAt` and `kindOfNode` refine the hit and the keyboard anchor where they are supplied.\n */\nexport function openContextMenu(\n deps: ActionDeps,\n params?: Record<string, unknown>,\n anchorOf: (deps: ActionDeps) => Point | null = keyboardAnchor,\n): boolean {\n const host = deps.menuHost;\n if (!host) return false;\n const p = params ?? {};\n if (typeof p.clientX === 'number' && typeof p.worldX === 'number') {\n const world = { x: p.worldX, y: p.worldY as number };\n const { hit, select } = menuHitFor(deps, world);\n if (select) deps.selection?.set([asNodeId(select)]);\n return host.open({\n hit,\n client: { x: p.clientX, y: p.clientY as number }, world, source: 'pointer',\n });\n }\n const world = anchorOf(deps);\n const client = world && deps.worldToClient?.(world.x, world.y);\n if (!world || !client) return false;\n return host.open({ hit: menuHitFor(deps).hit, client, world, source: 'keyboard' });\n}\n\nconst INITIAL = [{ channel: '*', phase: 'initial' }] as const;\n\n/**\n * Opens the context menu: for the pointer on a right-click or an unclaimed\n * long-press, selecting the shape under it first; for the keyboard on\n * Shift+F10 or the ContextMenu key, at the selection or else the middle of the view.\n */\nexport const contextMenuAction: Action & { requires: string[] } = {\n id: 'menu.context',\n label: 'Show Context Menu',\n defaultBinding: [\n { spec: { kind: 'contextMenu' }, opts: { id: 'menu.context.contextMenu' } },\n { spec: { kind: 'key', key: 'F10', mods: { shift: true }, phase: [...INITIAL] }, opts: { id: 'menu.context.key' } },\n { spec: { kind: 'key', key: 'ContextMenu', phase: [...INITIAL] }, opts: { id: 'menu.context.menuKey' } },\n ],\n requires: ['menuHost', 'selection', 'scene', 'poseDescriptor', 'view', 'worldToClient', 'hitAt', 'kindOfNode', 'enteredGroup'],\n // Disabled when no menu would open, so the dispatcher leaves the press, click and drag to whatever else is bound.\n enabled: (deps, at) => (deps?.menuHost?.has({ hit: menuHitFor(deps, at).hit, client: { x: 0, y: 0 }, world: at })\n ? true\n : ActionDisabledReason.NotApplicable),\n invoker: { timing: 'immediate', run: (deps, params) => { openContextMenu(deps, params); } },\n};\n"],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ import { paintInheritors } from "../../../core/scene/inheritedPaint.js";
1
2
  import { defaultCommitAdapter } from "../defaultCommitAdapter.js";
2
3
  import { createSetDataOp } from "../../../core/ops/setData.js";
3
4
  import { ActionDisabledReason } from "@weasel-js/routing";
@@ -43,7 +44,7 @@ function createPaintAction(spec) {
43
44
  const ids = selection.get();
44
45
  if (ids.length === 0) return {};
45
46
  const fallback = opts?.params;
46
- const pick = ((key) => ctx.params?.[key] ?? fallback?.[key]);
47
+ const pick = ((key) => ctx.params?.[key] !== void 0 ? ctx.params[key] : fallback?.[key]);
47
48
  const startData = /* @__PURE__ */ new Map();
48
49
  for (const id of ids) {
49
50
  const node = scene.get(id);
@@ -58,6 +59,8 @@ function createPaintAction(spec) {
58
59
  applyOps
59
60
  };
60
61
  refreshPreviews(scratch);
62
+ const key = spec.dataKey;
63
+ const inheritors = key === "fill" || key === "stroke" ? [...new Set(ids.flatMap((id) => paintInheritors(scene, id, key)))].filter((id) => !startData.has(id)) : [];
61
64
  return {
62
65
  onMove(moveCtx) {
63
66
  const next = spec.readParams(scratch.state, moveCtx.params);
@@ -92,7 +95,7 @@ function createPaintAction(spec) {
92
95
  }
93
96
  scratch.previews.clear();
94
97
  },
95
- previewIds: () => scratch.previews.keys(),
98
+ previewIds: () => scratch.previews.size === 0 ? [] : [...scratch.previews.keys(), ...inheritors],
96
99
  previewData: (id) => scratch.previews.get(id) ?? null
97
100
  };
98
101
  }
@@ -1 +1 @@
1
- {"version":3,"file":"createPaintAction.js","names":[],"sources":["../../../../src/interactions/actions/defaults/createPaintAction.ts"],"sourcesContent":["import type { Action } from '@weasel-js/routing';\nimport type { InvocationCtx, OngoingHandle, BindingOpts } from '@weasel-js/routing';\nimport { ActionDisabledReason } from '@weasel-js/routing';\nimport type { Scene, NodeId } from 'core/scene/types';\nimport type { Op } from 'core/ops/types';\nimport { createSetDataOp } from 'core/ops/setData';\nimport { defaultCommitAdapter } from '../defaultCommitAdapter';\n\n/** The node data one paint action reads and writes: its own key, nothing else. */\ntype PaintData<K extends string, TValue> = { [P in K]?: TValue | null };\n\ntype Params = Record<string, unknown> | undefined;\n\n/** Read a param from the invocation, falling back to the binding's. */\nexport type PickParam = <T>(key: string) => T | undefined;\n\n/**\n * What distinguishes one paint action from another.\n *\n * `TState` is the action's gesture state. It is a reducer, not a paint:\n * `setFill` and `setStroke` supersede a paint with a later color, which no\n * per-field merge of the params can express.\n */\nexport interface PaintActionSpec<TState, TValue, K extends string> {\n id: string;\n label: string;\n /** The `data` key this action owns. */\n dataKey: K;\n /** Gesture state at start. */\n initialState(pick: PickParam): TState;\n /** The state one onMove tick moves to, or `null` when its params carry\n * nothing this action reads — the preview then stands. */\n readParams(prev: TState, params: Params): TState | null;\n /** The value to write for one node, from that node's value at gesture start.\n * `null` writes the absence of paint, which is a value like any other —\n * a node with `fill: null` paints no fill. */\n merge(prev: TValue | null | undefined, state: TState): TValue | null;\n}\n\ninterface Scratch<TState, TValue, K extends string> {\n ids: NodeId[];\n scene: Scene<PaintData<K, TValue>, string, unknown>;\n /** Data snapshot at gesture start, keyed by node id. */\n startData: Map<NodeId, PaintData<K, TValue>>;\n state: TState;\n /** Preview data entries — the merged value per selected node. */\n previews: Map<NodeId, PaintData<K, TValue>>;\n /** Consumer commit hook captured at gesture start; undefined falls back to\n * `scene.applyBatch`. */\n applyOps?: (ops: Op[], label: string) => void;\n}\n\n/**\n * The ongoing-action body the paint actions share: it previews without\n * touching the scene, and commits one batch (one undo entry) through the\n * consumer `applyOps` hook when present, else `scene.applyBatch`.\n *\n * The `from` data is re-read at commit rather than reused from the start\n * snapshot, so a concurrent edit to a field this action does not own is not\n * clobbered.\n */\nexport function createPaintAction<TState, TValue, K extends string>(\n spec: PaintActionSpec<TState, TValue, K>,\n): Action & { requires: string[] } {\n type Data = PaintData<K, TValue>;\n\n const refreshPreviews = (scratch: Scratch<TState, TValue, K>): void => {\n scratch.previews.clear();\n for (const id of scratch.ids) {\n const prev = scratch.startData.get(id);\n const next = spec.merge(prev?.[spec.dataKey], scratch.state);\n scratch.previews.set(id, { ...(prev ?? {}), [spec.dataKey]: next } as Data);\n }\n };\n\n return {\n id: spec.id,\n label: spec.label,\n eligible: { capability: 'applies-fill' },\n requires: ['selection', 'scene', 'applyOps'],\n invoker: {\n timing: 'ongoing',\n start(ctx: InvocationCtx, opts?: BindingOpts): OngoingHandle {\n const selection = ctx.deps.selection;\n const scene = ctx.deps.scene as Scene<Data, string, unknown> | undefined;\n const applyOps = ctx.deps.applyOps;\n\n if (!selection || !scene) return {};\n\n const ids = selection.get() as NodeId[];\n if (ids.length === 0) return {};\n\n const fallback = opts?.params as Params;\n const pick = (<T>(key: string) =>\n (ctx.params?.[key] ?? fallback?.[key]) as T | undefined) as PickParam;\n\n const startData = new Map<NodeId, Data>();\n for (const id of ids) {\n const node = scene.get(id);\n if (node) startData.set(id, { ...(node.data as Data) });\n }\n\n const scratch: Scratch<TState, TValue, K> = {\n ids,\n scene,\n startData,\n state: spec.initialState(pick),\n previews: new Map(),\n applyOps,\n };\n refreshPreviews(scratch);\n\n return {\n onMove(moveCtx: InvocationCtx): void {\n const next = spec.readParams(scratch.state, moveCtx.params);\n if (next === null) return;\n scratch.state = next;\n refreshPreviews(scratch);\n },\n onEnd(_endCtx: InvocationCtx, reason: 'commit' | 'cancel'): void {\n if (reason === 'cancel') {\n scratch.previews.clear();\n return;\n }\n const ops: Op[] = [];\n for (const id of scratch.ids) {\n const merged = spec.merge(\n scratch.startData.get(id)?.[spec.dataKey],\n scratch.state,\n );\n const nodeNow = scratch.scene.get(id);\n if (!nodeNow) continue;\n const from = { ...(nodeNow.data as object) } as Data;\n const to = { ...from, [spec.dataKey]: merged } as Data;\n ops.push(createSetDataOp<Data>({ id: id as string, from, to }));\n }\n if (ops.length > 0) {\n if (scratch.applyOps) scratch.applyOps(ops, spec.label);\n else scratch.scene.applyBatch(ops, spec.label, defaultCommitAdapter(scratch.scene, selection.adapterMethods));\n }\n scratch.previews.clear();\n },\n previewIds: () => scratch.previews.keys(),\n previewData: (id: string) => scratch.previews.get(id as unknown as NodeId) ?? null,\n };\n },\n },\n enabled: (deps) => {\n const sel = deps?.selection;\n if (!sel || (sel.get() as unknown[]).length === 0) {\n return ActionDisabledReason.SelectionRequired;\n }\n return true;\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;AA6DA,SAAgB,kBACd,MACiC;CAGjC,MAAM,mBAAmB,YAA8C;EACrE,QAAQ,SAAS,MAAM;EACvB,KAAK,MAAM,MAAM,QAAQ,KAAK;GAC5B,MAAM,OAAO,QAAQ,UAAU,IAAI,EAAE;GACrC,MAAM,OAAO,KAAK,MAAM,OAAO,KAAK,UAAU,QAAQ,KAAK;GAC3D,QAAQ,SAAS,IAAI,IAAI;IAAE,GAAI,QAAQ,CAAC;KAAK,KAAK,UAAU;GAAK,CAAS;EAC5E;CACF;CAEA,OAAO;EACL,IAAI,KAAK;EACT,OAAO,KAAK;EACZ,UAAU,EAAE,YAAY,eAAe;EACvC,UAAU;GAAC;GAAa;GAAS;EAAU;EAC3C,SAAS;GACP,QAAQ;GACR,MAAM,KAAoB,MAAmC;IAC3D,MAAM,YAAY,IAAI,KAAK;IAC3B,MAAM,QAAQ,IAAI,KAAK;IACvB,MAAM,WAAW,IAAI,KAAK;IAE1B,IAAI,CAAC,aAAa,CAAC,OAAO,OAAO,CAAC;IAElC,MAAM,MAAM,UAAU,IAAI;IAC1B,IAAI,IAAI,WAAW,GAAG,OAAO,CAAC;IAE9B,MAAM,WAAW,MAAM;IACvB,MAAM,SAAY,QACf,IAAI,SAAS,QAAQ,WAAW;IAEnC,MAAM,4BAAY,IAAI,IAAkB;IACxC,KAAK,MAAM,MAAM,KAAK;KACpB,MAAM,OAAO,MAAM,IAAI,EAAE;KACzB,IAAI,MAAM,UAAU,IAAI,IAAI,EAAE,GAAI,KAAK,KAAc,CAAC;IACxD;IAEA,MAAM,UAAsC;KAC1C;KACA;KACA;KACA,OAAO,KAAK,aAAa,IAAI;KAC7B,0BAAU,IAAI,IAAI;KAClB;IACF;IACA,gBAAgB,OAAO;IAEvB,OAAO;KACL,OAAO,SAA8B;MACnC,MAAM,OAAO,KAAK,WAAW,QAAQ,OAAO,QAAQ,MAAM;MAC1D,IAAI,SAAS,MAAM;MACnB,QAAQ,QAAQ;MAChB,gBAAgB,OAAO;KACzB;KACA,MAAM,SAAwB,QAAmC;MAC/D,IAAI,WAAW,UAAU;OACvB,QAAQ,SAAS,MAAM;OACvB;MACF;MACA,MAAM,MAAY,CAAC;MACnB,KAAK,MAAM,MAAM,QAAQ,KAAK;OAC5B,MAAM,SAAS,KAAK,MAClB,QAAQ,UAAU,IAAI,EAAE,CAAC,GAAG,KAAK,UACjC,QAAQ,KACV;OACA,MAAM,UAAU,QAAQ,MAAM,IAAI,EAAE;OACpC,IAAI,CAAC,SAAS;OACd,MAAM,OAAO,EAAE,GAAI,QAAQ,KAAgB;OAC3C,MAAM,KAAK;QAAE,GAAG;SAAO,KAAK,UAAU;OAAO;OAC7C,IAAI,KAAK,gBAAsB;QAAM;QAAc;QAAM;OAAG,CAAC,CAAC;MAChE;MACA,IAAI,IAAI,SAAS,GAAG;OAClB,IAAI,QAAQ,UAAU,QAAQ,SAAS,KAAK,KAAK,KAAK;YACjD,QAAQ,MAAM,WAAW,KAAK,KAAK,OAAO,qBAAqB,QAAQ,OAAO,UAAU,cAAc,CAAC;MAC9G;MACA,QAAQ,SAAS,MAAM;KACzB;KACA,kBAAkB,QAAQ,SAAS,KAAK;KACxC,cAAc,OAAe,QAAQ,SAAS,IAAI,EAAuB,KAAK;IAChF;GACF;EACF;EACA,UAAU,SAAS;GACjB,MAAM,MAAM,MAAM;GAClB,IAAI,CAAC,OAAQ,IAAI,IAAI,CAAC,CAAe,WAAW,GAC9C,OAAO,qBAAqB;GAE9B,OAAO;EACT;CACF;AACF"}
1
+ {"version":3,"file":"createPaintAction.js","names":[],"sources":["../../../../src/interactions/actions/defaults/createPaintAction.ts"],"sourcesContent":["import type { Action } from '@weasel-js/routing';\nimport type { InvocationCtx, OngoingHandle, BindingOpts } from '@weasel-js/routing';\nimport { ActionDisabledReason } from '@weasel-js/routing';\nimport type { Scene, NodeId } from 'core/scene/types';\nimport type { Op } from 'core/ops/types';\nimport { createSetDataOp } from 'core/ops/setData';\nimport { defaultCommitAdapter } from '../defaultCommitAdapter';\nimport { paintInheritors } from 'core/scene/inheritedPaint';\n\n/** The node data one paint action reads and writes: its own key, nothing else. */\ntype PaintData<K extends string, TValue> = { [P in K]?: TValue | null };\n\ntype Params = Record<string, unknown> | undefined;\n\n/** Read a param from the invocation, falling back to the binding's. */\nexport type PickParam = <T>(key: string) => T | undefined;\n\n/**\n * What distinguishes one paint action from another.\n *\n * `TState` is the action's gesture state. It is a reducer, not a paint:\n * `setFill` and `setStroke` supersede a paint with a later color, which no\n * per-field merge of the params can express.\n */\nexport interface PaintActionSpec<TState, TValue, K extends string> {\n id: string;\n label: string;\n /** The `data` key this action owns. */\n dataKey: K;\n /** Gesture state at start. */\n initialState(pick: PickParam): TState;\n /** The state one onMove tick moves to, or `null` when its params carry\n * nothing this action reads — the preview then stands. */\n readParams(prev: TState, params: Params): TState | null;\n /** The value to write for one node, from that node's value at gesture start.\n * `null` writes the absence of paint, which is a value like any other —\n * a node with `fill: null` paints no fill. */\n merge(prev: TValue | null | undefined, state: TState): TValue | null;\n}\n\ninterface Scratch<TState, TValue, K extends string> {\n ids: NodeId[];\n scene: Scene<PaintData<K, TValue>, string, unknown>;\n /** Data snapshot at gesture start, keyed by node id. */\n startData: Map<NodeId, PaintData<K, TValue>>;\n state: TState;\n /** Preview data entries — the merged value per selected node. */\n previews: Map<NodeId, PaintData<K, TValue>>;\n /** Consumer commit hook captured at gesture start; undefined falls back to\n * `scene.applyBatch`. */\n applyOps?: (ops: Op[], label: string) => void;\n}\n\n/**\n * The ongoing-action body the paint actions share: it previews without\n * touching the scene, and commits one batch (one undo entry) through the\n * consumer `applyOps` hook when present, else `scene.applyBatch`.\n *\n * The `from` data is re-read at commit rather than reused from the start\n * snapshot, so a concurrent edit to a field this action does not own is not\n * clobbered.\n */\nexport function createPaintAction<TState, TValue, K extends string>(\n spec: PaintActionSpec<TState, TValue, K>,\n): Action & { requires: string[] } {\n type Data = PaintData<K, TValue>;\n\n const refreshPreviews = (scratch: Scratch<TState, TValue, K>): void => {\n scratch.previews.clear();\n for (const id of scratch.ids) {\n const prev = scratch.startData.get(id);\n const next = spec.merge(prev?.[spec.dataKey], scratch.state);\n scratch.previews.set(id, { ...(prev ?? {}), [spec.dataKey]: next } as Data);\n }\n };\n\n return {\n id: spec.id,\n label: spec.label,\n eligible: { capability: 'applies-fill' },\n requires: ['selection', 'scene', 'applyOps'],\n invoker: {\n timing: 'ongoing',\n start(ctx: InvocationCtx, opts?: BindingOpts): OngoingHandle {\n const selection = ctx.deps.selection;\n const scene = ctx.deps.scene as Scene<Data, string, unknown> | undefined;\n const applyOps = ctx.deps.applyOps;\n\n if (!selection || !scene) return {};\n\n const ids = selection.get() as NodeId[];\n if (ids.length === 0) return {};\n\n const fallback = opts?.params as Params;\n // `??` would lose a `paint: null`, which is None, not \"no paint given\".\n const pick = (<T>(key: string) =>\n (ctx.params?.[key] !== undefined ? ctx.params[key] : fallback?.[key]) as T | undefined) as PickParam;\n\n const startData = new Map<NodeId, Data>();\n for (const id of ids) {\n const node = scene.get(id);\n if (node) startData.set(id, { ...(node.data as Data) });\n }\n\n const scratch: Scratch<TState, TValue, K> = {\n ids,\n scene,\n startData,\n state: spec.initialState(pick),\n previews: new Map(),\n applyOps,\n };\n refreshPreviews(scratch);\n // Members that inherit the paint being changed preview with it.\n const key = spec.dataKey as string;\n const inheritors = key === 'fill' || key === 'stroke'\n ? [...new Set(ids.flatMap((id) => paintInheritors(scene, id, key)))].filter((id) => !startData.has(id as NodeId))\n : [];\n\n return {\n onMove(moveCtx: InvocationCtx): void {\n const next = spec.readParams(scratch.state, moveCtx.params);\n if (next === null) return;\n scratch.state = next;\n refreshPreviews(scratch);\n },\n onEnd(_endCtx: InvocationCtx, reason: 'commit' | 'cancel'): void {\n if (reason === 'cancel') {\n scratch.previews.clear();\n return;\n }\n const ops: Op[] = [];\n for (const id of scratch.ids) {\n const merged = spec.merge(\n scratch.startData.get(id)?.[spec.dataKey],\n scratch.state,\n );\n const nodeNow = scratch.scene.get(id);\n if (!nodeNow) continue;\n const from = { ...(nodeNow.data as object) } as Data;\n const to = { ...from, [spec.dataKey]: merged } as Data;\n ops.push(createSetDataOp<Data>({ id: id as string, from, to }));\n }\n if (ops.length > 0) {\n if (scratch.applyOps) scratch.applyOps(ops, spec.label);\n else scratch.scene.applyBatch(ops, spec.label, defaultCommitAdapter(scratch.scene, selection.adapterMethods));\n }\n scratch.previews.clear();\n },\n previewIds: () => (scratch.previews.size === 0 ? [] : [...scratch.previews.keys(), ...inheritors]),\n previewData: (id: string) => scratch.previews.get(id as unknown as NodeId) ?? null,\n };\n },\n },\n enabled: (deps) => {\n const sel = deps?.selection;\n if (!sel || (sel.get() as unknown[]).length === 0) {\n return ActionDisabledReason.SelectionRequired;\n }\n return true;\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;AA8DA,SAAgB,kBACd,MACiC;CAGjC,MAAM,mBAAmB,YAA8C;EACrE,QAAQ,SAAS,MAAM;EACvB,KAAK,MAAM,MAAM,QAAQ,KAAK;GAC5B,MAAM,OAAO,QAAQ,UAAU,IAAI,EAAE;GACrC,MAAM,OAAO,KAAK,MAAM,OAAO,KAAK,UAAU,QAAQ,KAAK;GAC3D,QAAQ,SAAS,IAAI,IAAI;IAAE,GAAI,QAAQ,CAAC;KAAK,KAAK,UAAU;GAAK,CAAS;EAC5E;CACF;CAEA,OAAO;EACL,IAAI,KAAK;EACT,OAAO,KAAK;EACZ,UAAU,EAAE,YAAY,eAAe;EACvC,UAAU;GAAC;GAAa;GAAS;EAAU;EAC3C,SAAS;GACP,QAAQ;GACR,MAAM,KAAoB,MAAmC;IAC3D,MAAM,YAAY,IAAI,KAAK;IAC3B,MAAM,QAAQ,IAAI,KAAK;IACvB,MAAM,WAAW,IAAI,KAAK;IAE1B,IAAI,CAAC,aAAa,CAAC,OAAO,OAAO,CAAC;IAElC,MAAM,MAAM,UAAU,IAAI;IAC1B,IAAI,IAAI,WAAW,GAAG,OAAO,CAAC;IAE9B,MAAM,WAAW,MAAM;IAEvB,MAAM,SAAY,QACf,IAAI,SAAS,SAAS,SAAY,IAAI,OAAO,OAAO,WAAW;IAElE,MAAM,4BAAY,IAAI,IAAkB;IACxC,KAAK,MAAM,MAAM,KAAK;KACpB,MAAM,OAAO,MAAM,IAAI,EAAE;KACzB,IAAI,MAAM,UAAU,IAAI,IAAI,EAAE,GAAI,KAAK,KAAc,CAAC;IACxD;IAEA,MAAM,UAAsC;KAC1C;KACA;KACA;KACA,OAAO,KAAK,aAAa,IAAI;KAC7B,0BAAU,IAAI,IAAI;KAClB;IACF;IACA,gBAAgB,OAAO;IAEvB,MAAM,MAAM,KAAK;IACjB,MAAM,aAAa,QAAQ,UAAU,QAAQ,WACzC,CAAC,GAAG,IAAI,IAAI,IAAI,SAAS,OAAO,gBAAgB,OAAO,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,OAAO,CAAC,UAAU,IAAI,EAAY,CAAC,IAC9G,CAAC;IAEL,OAAO;KACL,OAAO,SAA8B;MACnC,MAAM,OAAO,KAAK,WAAW,QAAQ,OAAO,QAAQ,MAAM;MAC1D,IAAI,SAAS,MAAM;MACnB,QAAQ,QAAQ;MAChB,gBAAgB,OAAO;KACzB;KACA,MAAM,SAAwB,QAAmC;MAC/D,IAAI,WAAW,UAAU;OACvB,QAAQ,SAAS,MAAM;OACvB;MACF;MACA,MAAM,MAAY,CAAC;MACnB,KAAK,MAAM,MAAM,QAAQ,KAAK;OAC5B,MAAM,SAAS,KAAK,MAClB,QAAQ,UAAU,IAAI,EAAE,CAAC,GAAG,KAAK,UACjC,QAAQ,KACV;OACA,MAAM,UAAU,QAAQ,MAAM,IAAI,EAAE;OACpC,IAAI,CAAC,SAAS;OACd,MAAM,OAAO,EAAE,GAAI,QAAQ,KAAgB;OAC3C,MAAM,KAAK;QAAE,GAAG;SAAO,KAAK,UAAU;OAAO;OAC7C,IAAI,KAAK,gBAAsB;QAAM;QAAc;QAAM;OAAG,CAAC,CAAC;MAChE;MACA,IAAI,IAAI,SAAS,GAAG;OAClB,IAAI,QAAQ,UAAU,QAAQ,SAAS,KAAK,KAAK,KAAK;YACjD,QAAQ,MAAM,WAAW,KAAK,KAAK,OAAO,qBAAqB,QAAQ,OAAO,UAAU,cAAc,CAAC;MAC9G;MACA,QAAQ,SAAS,MAAM;KACzB;KACA,kBAAmB,QAAQ,SAAS,SAAS,IAAI,CAAC,IAAI,CAAC,GAAG,QAAQ,SAAS,KAAK,GAAG,GAAG,UAAU;KAChG,cAAc,OAAe,QAAQ,SAAS,IAAI,EAAuB,KAAK;IAChF;GACF;EACF;EACA,UAAU,SAAS;GACjB,MAAM,MAAM,MAAM;GAClB,IAAI,CAAC,OAAQ,IAAI,IAAI,CAAC,CAAe,WAAW,GAC9C,OAAO,qBAAqB;GAE9B,OAAO;EACT;CACF;AACF"}
@@ -1,6 +1,7 @@
1
1
  import { defaultCommitAdapter } from "../defaultCommitAdapter.js";
2
2
  import { requiresSelection } from "./requiresSelection.js";
3
3
  import { createDeleteOp } from "../../../core/ops/delete.js";
4
+ import { hiddenSourcesTakenWith } from "../../../features/pathEffects/effectSources.js";
4
5
 
5
6
  //#region src/interactions/actions/defaults/delete.ts
6
7
  /** `id`'s slot among the scene roots or its parent's children, or `-1`. */
@@ -9,6 +10,15 @@ function hostIndex(scene, id) {
9
10
  return (node?.parent == null ? scene.roots : scene.childrenOf(node.parent)).indexOf(id);
10
11
  }
11
12
  /**
13
+ * Delete ops for the sources a removal of `ids` takes with it (see
14
+ * `hiddenSourcesTakenWith`), for an action whose own ops remove `ids` some
15
+ * other way. Append them after those ops: a delete finds its slot as it runs.
16
+ * Sources in `keep` stay.
17
+ */
18
+ function hiddenSourceDeleteOps(scene, ids, label, keep) {
19
+ return buildDeleteOps(scene, hiddenSourcesTakenWith(scene, ids, keep), label);
20
+ }
21
+ /**
12
22
  * Delete ops for `ids`, in the order given. Each op captures the node and its
13
23
  * host-array index BEFORE any removal, so `invert()` re-inserts at the right
14
24
  * slot and undo restores paint order. Ids with no live node are skipped.
@@ -24,10 +34,11 @@ function hostIndex(scene, id) {
24
34
  * survive depends on their order, and the ops are a cover of the selection
25
35
  * rather than its minimal set of roots.
26
36
  */
27
- function buildDeleteOps(scene, ids, label) {
37
+ function buildDeleteOps(scene, ids, label, opts = {}) {
38
+ const all = opts.takeHiddenSources ? [...ids, ...hiddenSourcesTakenWith(scene, ids)] : ids;
28
39
  const covered = /* @__PURE__ */ new Set();
29
40
  const ops = [];
30
- for (const id of ids) {
41
+ for (const id of all) {
31
42
  const node = scene.get(id);
32
43
  if (!node) continue;
33
44
  if (covered.has(id)) continue;
@@ -40,12 +51,12 @@ function buildDeleteOps(scene, ids, label) {
40
51
  }
41
52
  return ops;
42
53
  }
43
- /** The default commit: removes `ids` and their dependents as one undo entry,
44
- * then empties the selection. */
54
+ /** The default commit: removes `ids`, their dependents, and the sources a
55
+ * path effect among them hid, as one undo entry, then empties the selection. */
45
56
  function commitDeleteToScene(ids, deps) {
46
57
  const { selection, scene, applyOps } = deps;
47
58
  if (!selection || !scene) return;
48
- const ops = buildDeleteOps(scene, ids, "Delete");
59
+ const ops = buildDeleteOps(scene, ids, "Delete", { takeHiddenSources: true });
49
60
  if (ops.length > 0) {
50
61
  if (applyOps) applyOps(ops, "Delete");
51
62
  else scene.applyBatch(ops, "Delete", defaultCommitAdapter(scene, selection.adapterMethods));
@@ -60,14 +71,17 @@ function createDeleteAction(opts = {}) {
60
71
  label: "Delete",
61
72
  icon: /* @icon */ "core:delete",
62
73
  group: "edit",
63
- defaultBinding: {
64
- kind: "key",
65
- key: ["Delete", "Backspace"],
66
- phase: [{
67
- channel: "*",
68
- phase: "initial"
69
- }]
70
- },
74
+ defaultBinding: [{
75
+ spec: {
76
+ kind: "key",
77
+ key: ["Delete", "Backspace"],
78
+ phase: [{
79
+ channel: "*",
80
+ phase: "initial"
81
+ }]
82
+ },
83
+ opts: { id: "delete.key" }
84
+ }],
71
85
  eligible: { capability: "edits-page" },
72
86
  requires: [
73
87
  "scene",
@@ -94,5 +108,5 @@ function createDeleteAction(opts = {}) {
94
108
  var deleteAction = createDeleteAction();
95
109
 
96
110
  //#endregion
97
- export { buildDeleteOps, commitDeleteToScene, createDeleteAction, deleteAction };
111
+ export { buildDeleteOps, commitDeleteToScene, createDeleteAction, deleteAction, hiddenSourceDeleteOps };
98
112
  //# sourceMappingURL=delete.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"delete.js","names":[],"sources":["../../../../src/interactions/actions/defaults/delete.ts"],"sourcesContent":["import type { Node, NodeId, Scene } from 'core/scene/types';\nimport type { Op } from 'core/ops/types';\nimport { createDeleteOp } from 'core/ops/delete';\nimport { defaultCommitAdapter } from '../defaultCommitAdapter';\nimport type { Action, ActionDeps } from '@weasel-js/routing';\nimport { requiresSelection } from './requiresSelection';\nimport { icon } from '../../../icons.gen';\n\n/** `id`'s slot among the scene roots or its parent's children, or `-1`. */\nfunction hostIndex(scene: Scene<unknown, string, unknown>, id: NodeId): number {\n const node = scene.get(id);\n const siblings = node?.parent == null ? scene.roots : scene.childrenOf(node.parent);\n return siblings.indexOf(id);\n}\n\n/**\n * Delete ops for `ids`, in the order given. Each op captures the node and its\n * host-array index BEFORE any removal, so `invert()` re-inserts at the right\n * slot and undo restores paint order. Ids with no live node are skipped.\n *\n * Ids an already-emitted op will take are skipped: `removeNode` cascades both\n * the subtree and the dependents, so a second op for a node the first has taken\n * would throw `unknown node id` mid-batch — escaping the batch with the scene\n * already mutated. Selecting a container and its members does this.\n *\n * The covered set grows from the ops already emitted, not from the whole\n * selection, which is what settles a cycle: two ids that reach each other each\n * cover the other, and filtering both would delete nothing. So which ids\n * survive depends on their order, and the ops are a cover of the selection\n * rather than its minimal set of roots.\n */\nexport function buildDeleteOps(\n scene: Scene<unknown, string, unknown>,\n ids: readonly string[],\n label: string,\n): Op[] {\n const covered = new Set<string>();\n const ops: Op[] = [];\n for (const id of ids) {\n const node = scene.get(id as NodeId);\n if (!node) continue;\n if (covered.has(id)) continue;\n for (const taken of scene.removalClosure([id as NodeId])) covered.add(taken);\n ops.push(createDeleteOp<Node<unknown, string, unknown>>({\n node,\n index: hostIndex(scene, id as NodeId),\n label,\n }));\n }\n return ops;\n}\n\n/** Options for {@link createDeleteAction}. */\nexport interface DeleteActionOptions {\n /** Runs in place of the default, {@link commitDeleteToScene}. */\n commit?: (ids: readonly NodeId[], deps: ActionDeps) => void;\n}\n\n/** The default commit: removes `ids` and their dependents as one undo entry,\n * then empties the selection. */\nexport function commitDeleteToScene(ids: readonly NodeId[], deps: ActionDeps): void {\n const { selection, scene, applyOps } = deps;\n if (!selection || !scene) return;\n const ops = buildDeleteOps(scene, ids, 'Delete');\n if (ops.length > 0) {\n if (applyOps) applyOps(ops, 'Delete');\n else scene.applyBatch(ops, 'Delete', defaultCommitAdapter(scene, selection.adapterMethods));\n }\n selection.set([]);\n}\n\n/** Delete on Delete and Backspace: hands the selected ids to `commit`. */\nexport function createDeleteAction(opts: DeleteActionOptions = {}): Action & { requires: string[] } {\n const commit = opts.commit ?? commitDeleteToScene;\n return {\n id: 'delete',\n label: 'Delete',\n icon: icon('delete'),\n group: 'edit',\n // Suppressed while any tool is mid-gesture — accidentally hitting\n // Delete during a drag shouldn't wipe the selection out from under\n // the in-flight handle.\n defaultBinding: {\n kind: 'key',\n key: ['Delete', 'Backspace'],\n phase: [{ channel: '*', phase: 'initial' }],\n },\n eligible: { capability: 'edits-page' },\n requires: ['scene', 'selection', 'applyOps'],\n invoker: {\n timing: 'immediate',\n run: (deps) => {\n if (!deps.selection || !deps.scene) return;\n const ids = deps.selection.get() as readonly NodeId[];\n if (ids.length === 0) return;\n commit(ids, deps);\n },\n },\n enabled: requiresSelection,\n };\n}\n\n/**\n * Removes every selected node from the scene as one undo entry. Undo restores\n * everything the removal cascaded — a container's children and a deleted\n * node's dependents come back with it, at their own slots.\n */\nexport const deleteAction = createDeleteAction();\n"],"mappings":"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"}
1
+ {"version":3,"file":"delete.js","names":[],"sources":["../../../../src/interactions/actions/defaults/delete.ts"],"sourcesContent":["import type { Node, NodeId, Scene } from 'core/scene/types';\nimport type { Op } from 'core/ops/types';\nimport { createDeleteOp } from 'core/ops/delete';\nimport { defaultCommitAdapter } from '../defaultCommitAdapter';\nimport type { Action, ActionDeps } from '@weasel-js/routing';\nimport { requiresSelection } from './requiresSelection';\nimport { icon } from '../../../icons.gen';\nimport { hiddenSourcesTakenWith } from 'features/pathEffects/effectSources';\n\n/** `id`'s slot among the scene roots or its parent's children, or `-1`. */\nfunction hostIndex(scene: Scene<unknown, string, unknown>, id: NodeId): number {\n const node = scene.get(id);\n const siblings = node?.parent == null ? scene.roots : scene.childrenOf(node.parent);\n return siblings.indexOf(id);\n}\n\n/** Options for {@link buildDeleteOps}. */\nexport interface BuildDeleteOptions {\n /** Also delete the sources a path effect with `hideSources` among `ids` hid,\n * where nothing staying reads them — what Delete and Cut do. */\n takeHiddenSources?: boolean;\n}\n\n/**\n * Delete ops for the sources a removal of `ids` takes with it (see\n * `hiddenSourcesTakenWith`), for an action whose own ops remove `ids` some\n * other way. Append them after those ops: a delete finds its slot as it runs.\n * Sources in `keep` stay.\n */\nexport function hiddenSourceDeleteOps(\n scene: Scene<unknown, string, unknown>,\n ids: readonly NodeId[],\n label: string,\n keep?: ReadonlySet<NodeId>,\n): Op[] {\n return buildDeleteOps(scene, hiddenSourcesTakenWith(scene, ids, keep), label);\n}\n\n/**\n * Delete ops for `ids`, in the order given. Each op captures the node and its\n * host-array index BEFORE any removal, so `invert()` re-inserts at the right\n * slot and undo restores paint order. Ids with no live node are skipped.\n *\n * Ids an already-emitted op will take are skipped: `removeNode` cascades both\n * the subtree and the dependents, so a second op for a node the first has taken\n * would throw `unknown node id` mid-batch — escaping the batch with the scene\n * already mutated. Selecting a container and its members does this.\n *\n * The covered set grows from the ops already emitted, not from the whole\n * selection, which is what settles a cycle: two ids that reach each other each\n * cover the other, and filtering both would delete nothing. So which ids\n * survive depends on their order, and the ops are a cover of the selection\n * rather than its minimal set of roots.\n */\nexport function buildDeleteOps(\n scene: Scene<unknown, string, unknown>,\n ids: readonly string[],\n label: string,\n opts: BuildDeleteOptions = {},\n): Op[] {\n const all = opts.takeHiddenSources ? [...ids, ...hiddenSourcesTakenWith(scene, ids as readonly NodeId[])] : ids;\n const covered = new Set<string>();\n const ops: Op[] = [];\n for (const id of all) {\n const node = scene.get(id as NodeId);\n if (!node) continue;\n if (covered.has(id)) continue;\n for (const taken of scene.removalClosure([id as NodeId])) covered.add(taken);\n ops.push(createDeleteOp<Node<unknown, string, unknown>>({\n node,\n index: hostIndex(scene, id as NodeId),\n label,\n }));\n }\n return ops;\n}\n\n/** Options for {@link createDeleteAction}. */\nexport interface DeleteActionOptions {\n /** Runs in place of the default, {@link commitDeleteToScene}. */\n commit?: (ids: readonly NodeId[], deps: ActionDeps) => void;\n}\n\n/** The default commit: removes `ids`, their dependents, and the sources a\n * path effect among them hid, as one undo entry, then empties the selection. */\nexport function commitDeleteToScene(ids: readonly NodeId[], deps: ActionDeps): void {\n const { selection, scene, applyOps } = deps;\n if (!selection || !scene) return;\n const ops = buildDeleteOps(scene, ids, 'Delete', { takeHiddenSources: true });\n if (ops.length > 0) {\n if (applyOps) applyOps(ops, 'Delete');\n else scene.applyBatch(ops, 'Delete', defaultCommitAdapter(scene, selection.adapterMethods));\n }\n selection.set([]);\n}\n\n/** Delete on Delete and Backspace: hands the selected ids to `commit`. */\nexport function createDeleteAction(opts: DeleteActionOptions = {}): Action & { requires: string[] } {\n const commit = opts.commit ?? commitDeleteToScene;\n return {\n id: 'delete',\n label: 'Delete',\n icon: icon('delete'),\n group: 'edit',\n // Suppressed while any tool is mid-gesture — accidentally hitting\n // Delete during a drag shouldn't wipe the selection out from under\n // the in-flight handle.\n defaultBinding: [{\n spec: {\n kind: 'key',\n key: ['Delete', 'Backspace'],\n phase: [{ channel: '*', phase: 'initial' }],\n },\n opts: { id: 'delete.key' },\n }],\n eligible: { capability: 'edits-page' },\n requires: ['scene', 'selection', 'applyOps'],\n invoker: {\n timing: 'immediate',\n run: (deps) => {\n if (!deps.selection || !deps.scene) return;\n const ids = deps.selection.get() as readonly NodeId[];\n if (ids.length === 0) return;\n commit(ids, deps);\n },\n },\n enabled: requiresSelection,\n };\n}\n\n/**\n * Removes every selected node from the scene as one undo entry. Undo restores\n * everything the removal cascaded — a container's children and a deleted\n * node's dependents come back with it, at their own slots.\n */\nexport const deleteAction = createDeleteAction();\n"],"mappings":"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"}
@@ -49,14 +49,17 @@ var duplicateAction = {
49
49
  label: "Duplicate",
50
50
  icon: /* @icon */ "core:duplicate",
51
51
  group: "edit",
52
- defaultBinding: {
53
- kind: "key",
54
- key: ["d", "D"],
55
- mods: {
56
- mod: true,
57
- shift: true
58
- }
59
- },
52
+ defaultBinding: [{
53
+ spec: {
54
+ kind: "key",
55
+ key: ["d", "D"],
56
+ mods: {
57
+ mod: true,
58
+ shift: true
59
+ }
60
+ },
61
+ opts: { id: "duplicate.key" }
62
+ }],
60
63
  eligible: { capability: ["edits-page", "creates-selection"] },
61
64
  requires: [
62
65
  "scene",
@@ -1 +1 @@
1
- {"version":3,"file":"duplicate.js","names":[],"sources":["../../../../src/interactions/actions/defaults/duplicate.ts"],"sourcesContent":["import type { Action, ActionDeps } from '@weasel-js/routing';\nimport { composesFrames } from 'core/scene/composePose';\nimport { defaultCommitAdapter } from '../defaultCommitAdapter';\nimport { copySelection } from './copySubtree';\nimport { requiresSelection } from './requiresSelection';\nimport { nodeDescriptors, poseDescriptorOf } from '../poseDescriptorDep';\nimport { translatePoseViaDescriptor } from '../resize/geometry';\nimport { scenePoseFrame } from '../poseFrame';\nimport { storedDelta } from '../selectionSubtree';\nimport { recordTransform } from '../transform-again/memory';\nimport { icon } from '../../../icons.gen';\n\n/** Same nudge `sceneToAdapter.getPasteOffset` gives a paste, so duplicate and\n * paste land in the same place rather than disagreeing by a few units. */\nexport const DUPLICATE_OFFSET = 12;\n\n/**\n * Copy each selected node, with its subtree, offset by `(dx, dy)` in world\n * space whatever frame it is stored in, as one\n * undoable batch labeled `label`, and select the copies. Returns the copies'\n * ids, or null when nothing was copied.\n */\nexport function duplicateSelection(\n deps: ActionDeps,\n dx: number,\n dy: number,\n label = 'Duplicate',\n): string[] | null {\n const selection = deps.selection;\n const scene = deps.scene;\n const applyOps = deps.applyOps;\n if (!selection || !scene) return null;\n const ids = selection.get();\n if (ids.length === 0) return null;\n\n const descriptorOf = nodeDescriptors(scene, poseDescriptorOf(deps.poseDescriptor));\n const frame = scenePoseFrame(scene);\n // Under a frame a child's pose is relative, so offsetting the root\n // carries the subtree and offsetting a child again would double it.\n const offsetDescendants = !composesFrames(scene.composition);\n const { ops, copies } = copySelection(\n scene,\n ids,\n (id, node, isRoot) => {\n if (!isRoot && !offsetDescendants) return node.pose;\n const l = storedDelta(frame, descriptorOf(id), id, dx, dy);\n return translatePoseViaDescriptor(node.pose, l.dx, l.dy, descriptorOf(id));\n },\n label,\n );\n\n if (ops.length === 0) return null;\n if (applyOps) applyOps(ops, label);\n else scene.applyBatch(ops, label, defaultCommitAdapter(scene, selection.adapterMethods));\n selection.set(copies);\n return copies as string[];\n}\n\n/**\n * Static descriptor for the `duplicate` Action. Copies each selected node —\n * with its subtree, so duplicating a group produces a populated group — offset\n * by a small nudge, as one undoable batch, then selects the copies.\n */\nexport const duplicateAction: Action & { requires: string[] } = {\n id: 'duplicate',\n label: 'Duplicate',\n icon: icon('duplicate'),\n group: 'edit',\n // Cmd/Ctrl+D is `transformAgain`, which duplicates when nothing else is\n // there to repeat.\n defaultBinding: { kind: 'key', key: ['d', 'D'], mods: { mod: true, shift: true } },\n eligible: { capability: ['edits-page', 'creates-selection'] },\n // `selection` is read by the `enabled` gate as well as the invoker. An\n // undeclared read throws inside the dev-build deps Proxy before the gate can\n // answer, which is how this action spent a while doing nothing at all.\n requires: ['scene', 'selection', 'applyOps', 'poseDescriptor'],\n invoker: {\n timing: 'immediate',\n run: (deps) => {\n const scene = deps.scene;\n const selection = deps.selection;\n if (!scene || !selection) return;\n const copies = duplicateSelection(deps, DUPLICATE_OFFSET, DUPLICATE_OFFSET);\n if (copies) recordTransform(scene, { kind: 'duplicate', dx: DUPLICATE_OFFSET, dy: DUPLICATE_OFFSET }, copies);\n },\n },\n enabled: requiresSelection,\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"duplicate.js","names":[],"sources":["../../../../src/interactions/actions/defaults/duplicate.ts"],"sourcesContent":["import type { Action, ActionDeps } from '@weasel-js/routing';\nimport { composesFrames } from 'core/scene/composePose';\nimport { defaultCommitAdapter } from '../defaultCommitAdapter';\nimport { copySelection } from './copySubtree';\nimport { requiresSelection } from './requiresSelection';\nimport { nodeDescriptors, poseDescriptorOf } from '../poseDescriptorDep';\nimport { translatePoseViaDescriptor } from '../resize/geometry';\nimport { scenePoseFrame } from '../poseFrame';\nimport { storedDelta } from '../selectionSubtree';\nimport { recordTransform } from '../transform-again/memory';\nimport { icon } from '../../../icons.gen';\n\n/** Same nudge `sceneToAdapter.getPasteOffset` gives a paste, so duplicate and\n * paste land in the same place rather than disagreeing by a few units. */\nexport const DUPLICATE_OFFSET = 12;\n\n/**\n * Copy each selected node, with its subtree, offset by `(dx, dy)` in world\n * space whatever frame it is stored in, as one\n * undoable batch labeled `label`, and select the copies. Returns the copies'\n * ids, or null when nothing was copied.\n */\nexport function duplicateSelection(\n deps: ActionDeps,\n dx: number,\n dy: number,\n label = 'Duplicate',\n): string[] | null {\n const selection = deps.selection;\n const scene = deps.scene;\n const applyOps = deps.applyOps;\n if (!selection || !scene) return null;\n const ids = selection.get();\n if (ids.length === 0) return null;\n\n const descriptorOf = nodeDescriptors(scene, poseDescriptorOf(deps.poseDescriptor));\n const frame = scenePoseFrame(scene);\n // Under a frame a child's pose is relative, so offsetting the root\n // carries the subtree and offsetting a child again would double it.\n const offsetDescendants = !composesFrames(scene.composition);\n const { ops, copies } = copySelection(\n scene,\n ids,\n (id, node, isRoot) => {\n if (!isRoot && !offsetDescendants) return node.pose;\n const l = storedDelta(frame, descriptorOf(id), id, dx, dy);\n return translatePoseViaDescriptor(node.pose, l.dx, l.dy, descriptorOf(id));\n },\n label,\n );\n\n if (ops.length === 0) return null;\n if (applyOps) applyOps(ops, label);\n else scene.applyBatch(ops, label, defaultCommitAdapter(scene, selection.adapterMethods));\n selection.set(copies);\n return copies as string[];\n}\n\n/**\n * Static descriptor for the `duplicate` Action. Copies each selected node —\n * with its subtree, so duplicating a group produces a populated group — offset\n * by a small nudge, as one undoable batch, then selects the copies.\n */\nexport const duplicateAction: Action & { requires: string[] } = {\n id: 'duplicate',\n label: 'Duplicate',\n icon: icon('duplicate'),\n group: 'edit',\n // Cmd/Ctrl+D is `transformAgain`, which duplicates when nothing else is\n // there to repeat.\n defaultBinding: [{ spec: { kind: 'key', key: ['d', 'D'], mods: { mod: true, shift: true } }, opts: { id: 'duplicate.key' } }],\n eligible: { capability: ['edits-page', 'creates-selection'] },\n // `selection` is read by the `enabled` gate as well as the invoker. An\n // undeclared read throws inside the dev-build deps Proxy before the gate can\n // answer, which is how this action spent a while doing nothing at all.\n requires: ['scene', 'selection', 'applyOps', 'poseDescriptor'],\n invoker: {\n timing: 'immediate',\n run: (deps) => {\n const scene = deps.scene;\n const selection = deps.selection;\n if (!scene || !selection) return;\n const copies = duplicateSelection(deps, DUPLICATE_OFFSET, DUPLICATE_OFFSET);\n if (copies) recordTransform(scene, { kind: 'duplicate', dx: DUPLICATE_OFFSET, dy: DUPLICATE_OFFSET }, copies);\n },\n },\n enabled: requiresSelection,\n};\n"],"mappings":";;;;;;;;;;;;;AAcA,CAAA,CAAA,CAAA,CAAa,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAmB,CAAA,CAAA;;;;;;;AAQhC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAgB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACd,CAAA,CAAA,CAAA,CAAA,CAAA,CACA,CAAA,CAAA,CAAA,CACA,CAAA,CAAA,CAAA,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACS;AACjB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAY,CAAA,CAAA,CAAA,CAAA,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACvB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA;AACnB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAW,CAAA,CAAA,CAAA,CAAA,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACtB,CAAA,CAAA,CAAA,CAAA,CAAI,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAa,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAA,CAAA,CAAA,CAAA;AACjC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,CAAA,CAAA,CAAA,CAAI,CAAA;AAC1B,CAAA,CAAA,CAAA,CAAA,CAAI,CAAA,CAAA,CAAA,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAW,CAAA,CAAA,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAA,CAAA,CAAA,CAAA;AAE7B,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAe,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAgB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAiB,CAAA,CAAA,CAAA,CAAA,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAc,CAAC,CAAA;AACjF,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAe,CAAA,CAAA,CAAA,CAAA,CAAK,CAAA;AAGlC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAoB,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAe,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAW,CAAA;AAC3D,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAA,CAAE,CAAA,CAAA,CAAA,CAAA,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAW,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACtB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CACC,CAAA,CAAA,CAAA,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAW;AACpB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAmB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAA,CAAA,CAAA,CAAA,CAAK,CAAA,CAAA,CAAA,CAAA;AAC/C,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAA,CAAA,CAAA,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAY,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAa,CAAA,CAAE,CAAA,CAAA,CAAG,CAAA,CAAA,CAAA,CAAI,CAAA,CAAA,CAAA,CAAI,CAAA,CAAE,CAAA;AACzD,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAA2B,CAAA,CAAA,CAAA,CAAA,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAA,CAAE,CAAA,CAAA,CAAA,CAAI,CAAA,CAAE,CAAA,CAAA,CAAA,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAa,CAAA,CAAE,CAAC,CAAA;AAC3E,CAAA,CAAA,CAAA,CACA,CAAA,CAAA,CAAA,CAAA,CACF,CAAA;AAEA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAA,CAAA,CAAA,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAW,CAAA,CAAA,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAA,CAAA,CAAA,CAAA;AAC7B,CAAA,CAAA,CAAA,CAAA,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,CAAA,CAAA,CAAA,CAAA,CAAK,CAAA,CAAA,CAAA,CAAA,CAAK,CAAA;AAC5B,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAW,CAAA,CAAA,CAAA,CAAA,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAqB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAc,CAAC,CAAA;AACvF,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,CAAA,CAAA,CAAA,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAA;AACpB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACT;;;;;;AAOA,CAAA,CAAA,CAAA,CAAa,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAmD;AAC9D,CAAA,CAAA,CAAA,CAAA,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACJ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACP,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,aAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACN,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAGP,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAgB,CAAC;AAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM;AAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA;AAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC,CAAA,CAAA,CAAA,CAAA,CAAK,CAAA,CAAA,CAAG,CAAA;AAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM;AAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAA,CAAA,CAAA,CAAA;AAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAA,CAAA,CAAA;AAAK,CAAA,CAAA,CAAA;AAAE,CAAA,CAAA,CAAA;AAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAA,CAAE,CAAA,CAAA,CAAA,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAgB;AAAE,CAAA,CAAC,CAAA;AAC5H,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU,CAAA,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAY,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAc,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAmB,CAAA,CAAE,CAAA;AAI5D,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAU;AAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAa,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAY,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAgB,CAAA,CAAA;AAC7D,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS;AACP,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACR,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS;AACb,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA;AACnB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAY,CAAA,CAAA,CAAA,CAAA,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACvB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAW,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAC1B,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAmB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAkB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAgB,CAAA;AAC1E,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAgB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO;AAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAa,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAkB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AAAiB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAA;AAC9G,CAAA,CAAA;AACF,CAAA,CAAA;AACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACX,CAAA"}
@@ -0,0 +1,88 @@
1
+ import { pressTarget } from "../../../tools/builtin/pressTarget.js";
2
+ import { ActionDisabledReason } from "@weasel-js/routing";
3
+
4
+ //#region src/interactions/actions/defaults/enterGroup.ts
5
+ var inside = (b, p) => p.x >= b.x && p.x <= b.x + b.width && p.y >= b.y && p.y <= b.y + b.height;
6
+ /**
7
+ * Leaves every entered group whose box does not hold `p`, innermost first. A press that lands
8
+ * inside the entered group's box stays in it, and so does one on a group with no box to read.
9
+ */
10
+ function leaveGroupsOutside(entered, boxOf, p) {
11
+ for (let id = entered.get(); id !== null; id = entered.get()) {
12
+ const box = boxOf(id);
13
+ if (box === null || inside(box, p)) return;
14
+ entered.leave();
15
+ if (entered.get() === id) return;
16
+ }
17
+ }
18
+ /**
19
+ * `group.enter` — enters the group a press at the point would select. Bound to a double-click
20
+ * on a body by `useSelectTool`. It declines where that is not a group, so the double-click
21
+ * falls through to text editing, path editing and the mode triggers.
22
+ */
23
+ function createEnterGroupAction(opts) {
24
+ const targetAt = (deps, p) => {
25
+ const entered = deps?.enteredGroup;
26
+ if (!entered || !p) return null;
27
+ const hit = opts.pickHit(p.x, p.y);
28
+ if (hit === null) return null;
29
+ const target = pressTarget(opts.tree, hit, entered.get());
30
+ return opts.tree.getNode(target)?.kind === "group" ? target : null;
31
+ };
32
+ return {
33
+ id: "group.enter",
34
+ label: "Enter group",
35
+ eligible: { capability: "creates-selection" },
36
+ requires: ["enteredGroup"],
37
+ enabled: (deps, at) => targetAt(deps, at) !== null ? true : ActionDisabledReason.NotApplicable,
38
+ invoker: {
39
+ timing: "immediate",
40
+ run: (deps, params) => {
41
+ const x = params?.worldX, y = params?.worldY;
42
+ const target = typeof x === "number" && typeof y === "number" ? targetAt(deps, {
43
+ x,
44
+ y
45
+ }) : null;
46
+ if (target !== null) deps.enteredGroup?.enter(target);
47
+ }
48
+ }
49
+ };
50
+ }
51
+ /**
52
+ * `group.leave` — Escape leaves the entered group for the one above it; a press outside the
53
+ * entered group's box leaves every group that box does not hold. With nothing entered it
54
+ * declines, so Escape clears the selection as before, and it declines while path anchors are
55
+ * being edited, so that Escape exits the edit first.
56
+ */
57
+ function createLeaveGroupAction(opts) {
58
+ return {
59
+ id: "group.leave",
60
+ label: "Leave group",
61
+ eligible: { capability: "creates-selection" },
62
+ requires: ["enteredGroup", "editAnchors"],
63
+ enabled: (deps, at) => {
64
+ const here = deps?.enteredGroup?.get() ?? null;
65
+ if (here === null || deps?.editAnchors?.editingId) return ActionDisabledReason.NotApplicable;
66
+ if (!at) return true;
67
+ const box = opts.boxOf(here);
68
+ return box !== null && !inside(box, at) ? true : ActionDisabledReason.NotApplicable;
69
+ },
70
+ invoker: {
71
+ timing: "immediate",
72
+ run: (deps, params) => {
73
+ const entered = deps.enteredGroup;
74
+ if (!entered) return;
75
+ const x = params?.worldX, y = params?.worldY;
76
+ if (typeof x === "number" && typeof y === "number") leaveGroupsOutside(entered, opts.boxOf, {
77
+ x,
78
+ y
79
+ });
80
+ else entered.leave();
81
+ }
82
+ }
83
+ };
84
+ }
85
+
86
+ //#endregion
87
+ export { createEnterGroupAction, createLeaveGroupAction, leaveGroupsOutside };
88
+ //# sourceMappingURL=enterGroup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"enterGroup.js","names":[],"sources":["../../../../src/interactions/actions/defaults/enterGroup.ts"],"sourcesContent":["import type { Action, ActionDeps } from '@weasel-js/routing';\nimport { ActionDisabledReason } from '@weasel-js/routing';\nimport type { EnteredGroupApi } from 'canvas/deps/enteredGroup';\nimport type { NodeId } from 'core/scene/types';\nimport { pressTarget, type PressTargetTree } from '../../../tools/builtin/pressTarget';\n\ntype Point = { x: number; y: number };\ntype Box = { x: number; y: number; width: number; height: number };\n\n/** What `group.enter` reads: the node under a point and the tree above it. */\nexport interface EnterGroupOptions {\n /** The node under the point, before any group above it is considered. */\n pickHit: (worldX: number, worldY: number) => string | null;\n tree: PressTargetTree;\n}\n\n/** What `group.leave` reads: where a group's box is. */\nexport interface LeaveGroupOptions {\n boxOf: (id: string) => Box | null;\n}\n\nconst inside = (b: Box, p: Point) =>\n p.x >= b.x && p.x <= b.x + b.width && p.y >= b.y && p.y <= b.y + b.height;\n\n/**\n * Leaves every entered group whose box does not hold `p`, innermost first. A press that lands\n * inside the entered group's box stays in it, and so does one on a group with no box to read.\n */\nexport function leaveGroupsOutside(\n entered: EnteredGroupApi,\n boxOf: LeaveGroupOptions['boxOf'],\n p: Point,\n): void {\n for (let id = entered.get(); id !== null; id = entered.get()) {\n const box = boxOf(id);\n if (box === null || inside(box, p)) return;\n entered.leave();\n if (entered.get() === id) return;\n }\n}\n\n/**\n * `group.enter` — enters the group a press at the point would select. Bound to a double-click\n * on a body by `useSelectTool`. It declines where that is not a group, so the double-click\n * falls through to text editing, path editing and the mode triggers.\n */\nexport function createEnterGroupAction(opts: EnterGroupOptions): Action {\n const targetAt = (deps: ActionDeps | undefined, p: Point | undefined): string | null => {\n const entered = deps?.enteredGroup;\n if (!entered || !p) return null;\n const hit = opts.pickHit(p.x, p.y);\n if (hit === null) return null;\n const target = pressTarget(opts.tree, hit, entered.get());\n return (opts.tree.getNode(target) as { kind?: string } | undefined)?.kind === 'group' ? target : null;\n };\n return {\n id: 'group.enter',\n label: 'Enter group',\n eligible: { capability: 'creates-selection' },\n requires: ['enteredGroup'],\n enabled: (deps, at) => (targetAt(deps, at) !== null ? true : ActionDisabledReason.NotApplicable),\n invoker: {\n timing: 'immediate' as const,\n run: (deps, params) => {\n const x = params?.worldX, y = params?.worldY;\n const target = typeof x === 'number' && typeof y === 'number' ? targetAt(deps, { x, y }) : null;\n if (target !== null) deps.enteredGroup?.enter(target as NodeId);\n },\n },\n };\n}\n\n/**\n * `group.leave` — Escape leaves the entered group for the one above it; a press outside the\n * entered group's box leaves every group that box does not hold. With nothing entered it\n * declines, so Escape clears the selection as before, and it declines while path anchors are\n * being edited, so that Escape exits the edit first.\n */\nexport function createLeaveGroupAction(opts: LeaveGroupOptions): Action {\n return {\n id: 'group.leave',\n label: 'Leave group',\n eligible: { capability: 'creates-selection' },\n requires: ['enteredGroup', 'editAnchors'],\n enabled: (deps, at) => {\n const here = deps?.enteredGroup?.get() ?? null;\n if (here === null || deps?.editAnchors?.editingId) return ActionDisabledReason.NotApplicable;\n if (!at) return true;\n const box = opts.boxOf(here);\n return box !== null && !inside(box, at) ? true : ActionDisabledReason.NotApplicable;\n },\n invoker: {\n timing: 'immediate' as const,\n run: (deps, params) => {\n const entered = deps.enteredGroup;\n if (!entered) return;\n const x = params?.worldX, y = params?.worldY;\n if (typeof x === 'number' && typeof y === 'number') leaveGroupsOutside(entered, opts.boxOf, { x, y });\n else entered.leave();\n },\n },\n };\n}\n"],"mappings":";;;;AAqBA,IAAM,UAAU,GAAQ,MACtB,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE;;;;;AAMrE,SAAgB,mBACd,SACA,OACA,GACM;CACN,KAAK,IAAI,KAAK,QAAQ,IAAI,GAAG,OAAO,MAAM,KAAK,QAAQ,IAAI,GAAG;EAC5D,MAAM,MAAM,MAAM,EAAE;EACpB,IAAI,QAAQ,QAAQ,OAAO,KAAK,CAAC,GAAG;EACpC,QAAQ,MAAM;EACd,IAAI,QAAQ,IAAI,MAAM,IAAI;CAC5B;AACF;;;;;;AAOA,SAAgB,uBAAuB,MAAiC;CACtE,MAAM,YAAY,MAA8B,MAAwC;EACtF,MAAM,UAAU,MAAM;EACtB,IAAI,CAAC,WAAW,CAAC,GAAG,OAAO;EAC3B,MAAM,MAAM,KAAK,QAAQ,EAAE,GAAG,EAAE,CAAC;EACjC,IAAI,QAAQ,MAAM,OAAO;EACzB,MAAM,SAAS,YAAY,KAAK,MAAM,KAAK,QAAQ,IAAI,CAAC;EACxD,OAAQ,KAAK,KAAK,QAAQ,MAAM,CAAC,EAAoC,SAAS,UAAU,SAAS;CACnG;CACA,OAAO;EACL,IAAI;EACJ,OAAO;EACP,UAAU,EAAE,YAAY,oBAAoB;EAC5C,UAAU,CAAC,cAAc;EACzB,UAAU,MAAM,OAAQ,SAAS,MAAM,EAAE,MAAM,OAAO,OAAO,qBAAqB;EAClF,SAAS;GACP,QAAQ;GACR,MAAM,MAAM,WAAW;IACrB,MAAM,IAAI,QAAQ,QAAQ,IAAI,QAAQ;IACtC,MAAM,SAAS,OAAO,MAAM,YAAY,OAAO,MAAM,WAAW,SAAS,MAAM;KAAE;KAAG;IAAE,CAAC,IAAI;IAC3F,IAAI,WAAW,MAAM,KAAK,cAAc,MAAM,MAAgB;GAChE;EACF;CACF;AACF;;;;;;;AAQA,SAAgB,uBAAuB,MAAiC;CACtE,OAAO;EACL,IAAI;EACJ,OAAO;EACP,UAAU,EAAE,YAAY,oBAAoB;EAC5C,UAAU,CAAC,gBAAgB,aAAa;EACxC,UAAU,MAAM,OAAO;GACrB,MAAM,OAAO,MAAM,cAAc,IAAI,KAAK;GAC1C,IAAI,SAAS,QAAQ,MAAM,aAAa,WAAW,OAAO,qBAAqB;GAC/E,IAAI,CAAC,IAAI,OAAO;GAChB,MAAM,MAAM,KAAK,MAAM,IAAI;GAC3B,OAAO,QAAQ,QAAQ,CAAC,OAAO,KAAK,EAAE,IAAI,OAAO,qBAAqB;EACxE;EACA,SAAS;GACP,QAAQ;GACR,MAAM,MAAM,WAAW;IACrB,MAAM,UAAU,KAAK;IACrB,IAAI,CAAC,SAAS;IACd,MAAM,IAAI,QAAQ,QAAQ,IAAI,QAAQ;IACtC,IAAI,OAAO,MAAM,YAAY,OAAO,MAAM,UAAU,mBAAmB,SAAS,KAAK,OAAO;KAAE;KAAG;IAAE,CAAC;SAC/F,QAAQ,MAAM;GACrB;EACF;CACF;AACF"}
@@ -1,19 +1,24 @@
1
+ import { effectSourceFor } from "../../../features/pathEffects/effectSources.js";
1
2
  import { ActionDisabledReason, isBody } from "@weasel-js/routing";
2
3
 
3
4
  //#region src/interactions/actions/defaults/enterPathEdit.ts
4
5
  var enterPathEditAction = {
5
6
  id: "enterPathEdit",
6
7
  label: "Edit path anchors",
7
- defaultBinding: {
8
- kind: "doubleClick",
9
- target: { kindOf: isBody }
10
- },
11
- eligible: { mode: { in: ["normal", "isolation"] } },
8
+ defaultBinding: [{
9
+ spec: {
10
+ kind: "doubleClick",
11
+ target: { kindOf: isBody }
12
+ },
13
+ opts: { id: "enterPathEdit.doubleClick" }
14
+ }],
15
+ eligible: { mode: "normal" },
12
16
  requires: [
13
17
  "editAnchors",
14
18
  "selection",
15
19
  "nodeAtPoint",
16
- "hitAt"
20
+ "hitAt",
21
+ "scene"
17
22
  ],
18
23
  invoker: {
19
24
  timing: "immediate",
@@ -22,7 +27,8 @@ var enterPathEditAction = {
22
27
  const selection = deps.selection;
23
28
  if (!editAnchors || !selection) return;
24
29
  const x = params?.worldX, y = params?.worldY;
25
- const under = typeof x === "number" && typeof y === "number" ? deps.nodeAtPoint?.({
30
+ const pointed = typeof x === "number" && typeof y === "number";
31
+ const under = pointed ? deps.nodeAtPoint?.({
26
32
  x,
27
33
  y
28
34
  }) : null;
@@ -31,9 +37,13 @@ var enterPathEditAction = {
31
37
  return;
32
38
  }
33
39
  const ids = selection.get();
34
- for (const id of ids) if (editAnchors.getEditablePath(id)) {
35
- editAnchors.setEditingId(id);
36
- return;
40
+ const scene = deps.scene;
41
+ for (const id of ids) {
42
+ const target = (!pointed && scene ? effectSourceFor(scene, id, "path") : null) ?? id;
43
+ if (editAnchors.getEditablePath(target)) {
44
+ editAnchors.setEditingId(target);
45
+ return;
46
+ }
37
47
  }
38
48
  }
39
49
  },