@weasel-js/core 1.11.0 → 1.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (586) hide show
  1. package/CHANGELOG.md +611 -0
  2. package/README.md +1 -1
  3. package/dist/WeaselProvider.js +1 -1
  4. package/dist/affordances/pathAnchors.js +10 -6
  5. package/dist/affordances/pathAnchors.js.map +1 -1
  6. package/dist/animation/index.js +3 -3
  7. package/dist/animation/rig/bindRig.js +1 -1
  8. package/dist/animation/rig/rigNode.js.map +1 -1
  9. package/dist/barrel/canvas.js +9 -3
  10. package/dist/barrel/interactions.js +5 -4
  11. package/dist/barrel/paint.js +4 -4
  12. package/dist/barrel/paths.js +10 -6
  13. package/dist/barrel/renderer.js +5 -3
  14. package/dist/barrel/routing.js +7 -12
  15. package/dist/barrel/scene.js +9 -5
  16. package/dist/barrel/text.js +2 -2
  17. package/dist/barrel/viewport.js +9 -4
  18. package/dist/canvas/Canvas.js +5 -2
  19. package/dist/canvas/Canvas.js.map +1 -1
  20. package/dist/canvas/CanvasView.js +23 -34
  21. package/dist/canvas/CanvasView.js.map +1 -1
  22. package/dist/canvas/ModalityHud.js +1 -1
  23. package/dist/canvas/NodeShape.js +4 -1
  24. package/dist/canvas/NodeShape.js.map +1 -1
  25. package/dist/canvas/SceneCanvas/ActionsProviderIfRoot.js +1 -1
  26. package/dist/canvas/SceneCanvas/DepRegistryProviderIfRoot.js +1 -1
  27. package/dist/canvas/SceneCanvas/PointerProviderIfRoot.js +1 -1
  28. package/dist/canvas/SceneCanvas/SceneCanvasInput.js +17 -3
  29. package/dist/canvas/SceneCanvas/SceneCanvasInput.js.map +1 -1
  30. package/dist/canvas/SceneCanvas/SurfaceDeclarations.js +23 -0
  31. package/dist/canvas/SceneCanvas/SurfaceDeclarations.js.map +1 -0
  32. package/dist/canvas/SceneCanvas/builtinToolSets.js +30 -0
  33. package/dist/canvas/SceneCanvas/builtinToolSets.js.map +1 -0
  34. package/dist/canvas/SceneCanvas/canvasPassThrough.js +2 -0
  35. package/dist/canvas/SceneCanvas/canvasPassThrough.js.map +1 -1
  36. package/dist/canvas/SceneCanvas/coordTrace.js +5 -16
  37. package/dist/canvas/SceneCanvas/coordTrace.js.map +1 -1
  38. package/dist/canvas/SceneCanvas/defaultNodeProperties.js +5 -0
  39. package/dist/canvas/SceneCanvas/defaultNodeProperties.js.map +1 -1
  40. package/dist/canvas/SceneCanvas/features.js +45 -5
  41. package/dist/canvas/SceneCanvas/features.js.map +1 -1
  42. package/dist/canvas/SceneCanvas/props.js +1 -11
  43. package/dist/canvas/SceneCanvas/props.js.map +1 -1
  44. package/dist/canvas/SceneCanvas/scenePointQuery.js +7 -3
  45. package/dist/canvas/SceneCanvas/scenePointQuery.js.map +1 -1
  46. package/dist/canvas/SceneCanvas/toolRegistry.js +8 -4
  47. package/dist/canvas/SceneCanvas/toolRegistry.js.map +1 -1
  48. package/dist/canvas/SceneCanvas/useActionTunings.js +6 -1
  49. package/dist/canvas/SceneCanvas/useActionTunings.js.map +1 -1
  50. package/dist/canvas/SceneCanvas/useActionsPropResolver.js +1 -11
  51. package/dist/canvas/SceneCanvas/useActionsPropResolver.js.map +1 -1
  52. package/dist/canvas/SceneCanvas/useBuiltinShapeTools.js.map +1 -1
  53. package/dist/canvas/SceneCanvas/useBuiltinTools.js +2 -9
  54. package/dist/canvas/SceneCanvas/useBuiltinTools.js.map +1 -1
  55. package/dist/canvas/SceneCanvas/useCanvasDevtoolsRoot.js +94 -0
  56. package/dist/canvas/SceneCanvas/useCanvasDevtoolsRoot.js.map +1 -0
  57. package/dist/canvas/SceneCanvas/useCanvasSelection.js +7 -2
  58. package/dist/canvas/SceneCanvas/useCanvasSelection.js.map +1 -1
  59. package/dist/canvas/SceneCanvas/useCanvasTools.js +15 -10
  60. package/dist/canvas/SceneCanvas/useCanvasTools.js.map +1 -1
  61. package/dist/canvas/SceneCanvas/useNodeKinds.js +1 -1
  62. package/dist/canvas/SceneCanvas/useNodeKinds.js.map +1 -1
  63. package/dist/canvas/SceneCanvas/useSceneCanvasHandle.js +9 -3
  64. package/dist/canvas/SceneCanvas/useSceneCanvasHandle.js.map +1 -1
  65. package/dist/canvas/SceneCanvas/useSceneCanvasLayers.js +23 -4
  66. package/dist/canvas/SceneCanvas/useSceneCanvasLayers.js.map +1 -1
  67. package/dist/canvas/SceneCanvas/useSceneCanvasTools.js +2 -3
  68. package/dist/canvas/SceneCanvas/useSceneCanvasTools.js.map +1 -1
  69. package/dist/canvas/SceneCanvas/useSceneChrome.js +6 -7
  70. package/dist/canvas/SceneCanvas/useSceneChrome.js.map +1 -1
  71. package/dist/canvas/SceneCanvas/useSceneGestureDispatcher.js +24 -7
  72. package/dist/canvas/SceneCanvas/useSceneGestureDispatcher.js.map +1 -1
  73. package/dist/canvas/SceneCanvas/useScenePicking.js +2 -3
  74. package/dist/canvas/SceneCanvas/useScenePicking.js.map +1 -1
  75. package/dist/canvas/SceneCanvas/useSceneSelectTool.js +2 -1
  76. package/dist/canvas/SceneCanvas/useSceneSelectTool.js.map +1 -1
  77. package/dist/canvas/SceneCanvas/useSceneStandardActions.js +5 -5
  78. package/dist/canvas/SceneCanvas/useSceneStandardActions.js.map +1 -1
  79. package/dist/canvas/SceneCanvas.js +27 -24
  80. package/dist/canvas/SceneCanvas.js.map +1 -1
  81. package/dist/canvas/SurfaceCanvas.js +5 -22
  82. package/dist/canvas/SurfaceCanvas.js.map +1 -1
  83. package/dist/canvas/ViewMarker.js +35 -0
  84. package/dist/canvas/ViewMarker.js.map +1 -0
  85. package/dist/canvas/canvasRenderer.js +9 -5
  86. package/dist/canvas/canvasRenderer.js.map +1 -1
  87. package/dist/canvas/contextAttributes.js +14 -0
  88. package/dist/canvas/contextAttributes.js.map +1 -0
  89. package/dist/canvas/defaultDrawOne.js +2 -0
  90. package/dist/canvas/defaultDrawOne.js.map +1 -1
  91. package/dist/canvas/deps/booleans.js +2 -1
  92. package/dist/canvas/deps/booleans.js.map +1 -1
  93. package/dist/canvas/deps/editAnchors.js +9 -113
  94. package/dist/canvas/deps/editAnchors.js.map +1 -1
  95. package/dist/canvas/deps/hitTestArea.js +2 -2
  96. package/dist/canvas/deps/hitTestArea.js.map +1 -1
  97. package/dist/canvas/deps/insert.js +10 -4
  98. package/dist/canvas/deps/insert.js.map +1 -1
  99. package/dist/canvas/deps/pathEditCommits.js +189 -0
  100. package/dist/canvas/deps/pathEditCommits.js.map +1 -0
  101. package/dist/canvas/deps/snap.js +12 -9
  102. package/dist/canvas/deps/snap.js.map +1 -1
  103. package/dist/canvas/deps/transformFollowers.js +20 -0
  104. package/dist/canvas/deps/transformFollowers.js.map +1 -0
  105. package/dist/canvas/derivedPath.js +20 -1
  106. package/dist/canvas/derivedPath.js.map +1 -1
  107. package/dist/canvas/drawnBounds.js +38 -4
  108. package/dist/canvas/drawnBounds.js.map +1 -1
  109. package/dist/canvas/inheritedPaints.js +44 -0
  110. package/dist/canvas/inheritedPaints.js.map +1 -0
  111. package/dist/canvas/nodeShapes/derivedPainter.js +23 -16
  112. package/dist/canvas/nodeShapes/derivedPainter.js.map +1 -1
  113. package/dist/canvas/nodeShapes/nodePaint.js +13 -34
  114. package/dist/canvas/nodeShapes/nodePaint.js.map +1 -1
  115. package/dist/canvas/nodeShapes/pathPainter.js +12 -10
  116. package/dist/canvas/nodeShapes/pathPainter.js.map +1 -1
  117. package/dist/canvas/nodeShapes/rectFallbackPainter.js +4 -5
  118. package/dist/canvas/nodeShapes/rectFallbackPainter.js.map +1 -1
  119. package/dist/canvas/nodeShapes/shapePainter.js +12 -11
  120. package/dist/canvas/nodeShapes/shapePainter.js.map +1 -1
  121. package/dist/canvas/nodeShapes/textPainter.js +13 -12
  122. package/dist/canvas/nodeShapes/textPainter.js.map +1 -1
  123. package/dist/canvas/overlayRoleStrokes.js +12 -0
  124. package/dist/canvas/overlayRoleStrokes.js.map +1 -1
  125. package/dist/canvas/pathOverlay.js +27 -7
  126. package/dist/canvas/pathOverlay.js.map +1 -1
  127. package/dist/canvas/pickReach.js +3 -3
  128. package/dist/canvas/pickReach.js.map +1 -1
  129. package/dist/canvas/pickWalk.js +3 -1
  130. package/dist/canvas/pickWalk.js.map +1 -1
  131. package/dist/canvas/renderDebugSnapshot.js +1 -0
  132. package/dist/canvas/renderDebugSnapshot.js.map +1 -1
  133. package/dist/canvas/renderSceneToPixels.js +7 -6
  134. package/dist/canvas/renderSceneToPixels.js.map +1 -1
  135. package/dist/canvas/sceneAdapter.js.map +1 -1
  136. package/dist/canvas/sceneSlotWiring.js +2 -1
  137. package/dist/canvas/sceneSlotWiring.js.map +1 -1
  138. package/dist/canvas/sceneViewRender.js +2 -1
  139. package/dist/canvas/sceneViewRender.js.map +1 -1
  140. package/dist/canvas/surfaceContribution.js +12 -8
  141. package/dist/canvas/surfaceContribution.js.map +1 -1
  142. package/dist/canvas/useCanvasPaint.js +2 -1
  143. package/dist/canvas/useCanvasPaint.js.map +1 -1
  144. package/dist/canvas/useCanvasView.js +4 -2
  145. package/dist/canvas/useCanvasView.js.map +1 -1
  146. package/dist/canvas/useInFlightBounds.js +52 -0
  147. package/dist/canvas/useInFlightBounds.js.map +1 -0
  148. package/dist/canvas/useLayerStack.js +6 -2
  149. package/dist/canvas/useLayerStack.js.map +1 -1
  150. package/dist/canvas/useViewAim.js +121 -0
  151. package/dist/canvas/useViewAim.js.map +1 -0
  152. package/dist/canvas/useViewHelpers.js +7 -9
  153. package/dist/canvas/useViewHelpers.js.map +1 -1
  154. package/dist/canvas/useViewNesting.js +3 -2
  155. package/dist/canvas/useViewNesting.js.map +1 -1
  156. package/dist/canvas/useViewRegistrySurface.js +4 -2
  157. package/dist/canvas/useViewRegistrySurface.js.map +1 -1
  158. package/dist/canvas/viewMarkers.js +63 -0
  159. package/dist/canvas/viewMarkers.js.map +1 -0
  160. package/dist/canvas/viewRegistry.js +27 -1
  161. package/dist/canvas/viewRegistry.js.map +1 -1
  162. package/dist/clipboard.d.ts +3 -2
  163. package/dist/{clone-DZDrfIlU.d.ts → clone-C3e0OTuF.d.ts} +8 -21
  164. package/dist/clone.d.ts +4 -3
  165. package/dist/core/geometry/autoPoseDescriptor.js +1 -1
  166. package/dist/core/ops/setDependsOn.js +37 -0
  167. package/dist/core/ops/setDependsOn.js.map +1 -0
  168. package/dist/core/ops/writtenBy.js +53 -0
  169. package/dist/core/ops/writtenBy.js.map +1 -0
  170. package/dist/core/pages/fitViewToPage.js +12 -1
  171. package/dist/core/pages/fitViewToPage.js.map +1 -1
  172. package/dist/core/pages/pageEdits.js +163 -0
  173. package/dist/core/pages/pageEdits.js.map +1 -0
  174. package/dist/core/pages/pages.js +30 -1
  175. package/dist/core/pages/pages.js.map +1 -1
  176. package/dist/core/paint/meshKindLazy.js +59 -2
  177. package/dist/core/paint/meshKindLazy.js.map +1 -1
  178. package/dist/core/scene/NodeRouting.js +8 -3
  179. package/dist/core/scene/NodeRouting.js.map +1 -1
  180. package/dist/core/scene/arrivalWindow.js.map +1 -1
  181. package/dist/core/scene/carryDescendants.js +51 -0
  182. package/dist/core/scene/carryDescendants.js.map +1 -0
  183. package/dist/core/scene/clipNothing.js +13 -0
  184. package/dist/core/scene/clipNothing.js.map +1 -0
  185. package/dist/core/scene/depMemo.js +11 -3
  186. package/dist/core/scene/depMemo.js.map +1 -1
  187. package/dist/core/scene/dependents.js +7 -1
  188. package/dist/core/scene/dependents.js.map +1 -1
  189. package/dist/core/scene/derivedParts.js +10 -11
  190. package/dist/core/scene/derivedParts.js.map +1 -1
  191. package/dist/core/scene/docValues.js +57 -0
  192. package/dist/core/scene/docValues.js.map +1 -0
  193. package/dist/core/scene/editPass.js +111 -0
  194. package/dist/core/scene/editPass.js.map +1 -0
  195. package/dist/core/scene/effectivePose.js +13 -2
  196. package/dist/core/scene/effectivePose.js.map +1 -1
  197. package/dist/core/scene/fieldEdits.js +4 -1
  198. package/dist/core/scene/fieldEdits.js.map +1 -1
  199. package/dist/core/scene/fontReads.js +37 -0
  200. package/dist/core/scene/fontReads.js.map +1 -0
  201. package/dist/core/scene/historyFacade.js +1 -0
  202. package/dist/core/scene/historyFacade.js.map +1 -1
  203. package/dist/core/scene/inheritedPaint.js +75 -0
  204. package/dist/core/scene/inheritedPaint.js.map +1 -0
  205. package/dist/core/scene/kitRegistry.js +5 -0
  206. package/dist/core/scene/kitRegistry.js.map +1 -1
  207. package/dist/core/scene/layoutPass.js +28 -3
  208. package/dist/core/scene/layoutPass.js.map +1 -1
  209. package/dist/core/scene/nodeMemo.js +15 -7
  210. package/dist/core/scene/nodeMemo.js.map +1 -1
  211. package/dist/core/scene/pathEffects/blend.js.map +1 -1
  212. package/dist/core/scene/pathEffects/derive.js +7 -2
  213. package/dist/core/scene/pathEffects/derive.js.map +1 -1
  214. package/dist/core/scene/pathEffects/effects.js +3 -1
  215. package/dist/core/scene/pathEffects/effects.js.map +1 -1
  216. package/dist/core/scene/pathEffects/textAlong.js +95 -0
  217. package/dist/core/scene/pathEffects/textAlong.js.map +1 -0
  218. package/dist/core/scene/recorder.js +28 -19
  219. package/dist/core/scene/recorder.js.map +1 -1
  220. package/dist/core/scene/scene.js +15 -9
  221. package/dist/core/scene/scene.js.map +1 -1
  222. package/dist/core/scene/sceneChanges.js +13 -0
  223. package/dist/core/scene/sceneChanges.js.map +1 -0
  224. package/dist/core/scene/sceneEdits.js +8 -1
  225. package/dist/core/scene/sceneEdits.js.map +1 -1
  226. package/dist/core/scene/sceneMutators.js +1 -0
  227. package/dist/core/scene/sceneMutators.js.map +1 -1
  228. package/dist/core/scene/sceneRecording.js +20 -3
  229. package/dist/core/scene/sceneRecording.js.map +1 -1
  230. package/dist/core/scene/sceneSelection.js +4 -1
  231. package/dist/core/scene/sceneSelection.js.map +1 -1
  232. package/dist/core/scene/sceneState.js +11 -5
  233. package/dist/core/scene/sceneState.js.map +1 -1
  234. package/dist/core/scene/serialization.js +5 -3
  235. package/dist/core/scene/serialization.js.map +1 -1
  236. package/dist/core/scene/types.js.map +1 -1
  237. package/dist/core/scene/unitScopes.js +19 -1
  238. package/dist/core/scene/unitScopes.js.map +1 -1
  239. package/dist/core/selection/usePublishSceneSelection.js +6 -12
  240. package/dist/core/selection/usePublishSceneSelection.js.map +1 -1
  241. package/dist/core/shapeKinds.js +25 -11
  242. package/dist/core/shapeKinds.js.map +1 -1
  243. package/dist/{cornerHandles-Camw_yeu.d.ts → cornerHandles-p8fDIAKt.d.ts} +3 -2
  244. package/dist/debug/createDebugOverlayLayer.js +16 -111
  245. package/dist/debug/createDebugOverlayLayer.js.map +1 -1
  246. package/dist/debug/createDebugSink.js +2 -1
  247. package/dist/debug/createDebugSink.js.map +1 -1
  248. package/dist/debug/defaultTheme.js +4 -2
  249. package/dist/debug/defaultTheme.js.map +1 -1
  250. package/dist/debug/features.js +17 -0
  251. package/dist/debug/features.js.map +1 -0
  252. package/dist/debug/overlayPanels.js +117 -0
  253. package/dist/debug/overlayPanels.js.map +1 -0
  254. package/dist/debug/parseDebugFlags.js +4 -13
  255. package/dist/debug/parseDebugFlags.js.map +1 -1
  256. package/dist/{depSchema-Cgfu_G9s.d.ts → depSchema-mG19aEdD.d.ts} +174 -904
  257. package/dist/devtools/handlers.js +112 -0
  258. package/dist/devtools/handlers.js.map +1 -0
  259. package/dist/devtools/history.js +71 -0
  260. package/dist/devtools/history.js.map +1 -0
  261. package/dist/devtools/hook.js +74 -0
  262. package/dist/devtools/hook.js.map +1 -0
  263. package/dist/devtools/label.js +25 -0
  264. package/dist/devtools/label.js.map +1 -0
  265. package/dist/devtools/notices.js +58 -0
  266. package/dist/devtools/notices.js.map +1 -0
  267. package/dist/devtools/protocol.js +7 -0
  268. package/dist/devtools/protocol.js.map +1 -0
  269. package/dist/devtools/registry.js +90 -0
  270. package/dist/devtools/registry.js.map +1 -0
  271. package/dist/devtools/root.js +80 -0
  272. package/dist/devtools/root.js.map +1 -0
  273. package/dist/devtools/serialize.js +86 -0
  274. package/dist/devtools/serialize.js.map +1 -0
  275. package/dist/devtools/session.js +111 -0
  276. package/dist/devtools/session.js.map +1 -0
  277. package/dist/devtools/transport.js +67 -0
  278. package/dist/devtools/transport.js.map +1 -0
  279. package/dist/devtools/useDevtoolsRoot.js +81 -0
  280. package/dist/devtools/useDevtoolsRoot.js.map +1 -0
  281. package/dist/devtools-protocol.d.ts +435 -0
  282. package/dist/devtools-protocol.js +7 -0
  283. package/dist/devtools.d.ts +8 -0
  284. package/dist/devtools.js +12 -0
  285. package/dist/devtools.js.map +1 -0
  286. package/dist/features/chrome-caps/useHoverTracking.js +16 -10
  287. package/dist/features/chrome-caps/useHoverTracking.js.map +1 -1
  288. package/dist/features/ingestion/contentHandlers.js +25 -2
  289. package/dist/features/ingestion/contentHandlers.js.map +1 -1
  290. package/dist/features/measure/measureCommands.js +7 -5
  291. package/dist/features/measure/measureCommands.js.map +1 -1
  292. package/dist/features/measure/measureContribution.js +4 -2
  293. package/dist/features/measure/measureContribution.js.map +1 -1
  294. package/dist/features/modes/modeTriggers.js +7 -3
  295. package/dist/features/modes/modeTriggers.js.map +1 -1
  296. package/dist/features/pathEffects/effectSources.js +60 -0
  297. package/dist/features/pathEffects/effectSources.js.map +1 -0
  298. package/dist/features/pathEffects/readSource.js +17 -1
  299. package/dist/features/pathEffects/readSource.js.map +1 -1
  300. package/dist/features/pathEffects/textItems.js +53 -0
  301. package/dist/features/pathEffects/textItems.js.map +1 -0
  302. package/dist/features/pathEffects/useEffectSourcesLayer.js +57 -0
  303. package/dist/features/pathEffects/useEffectSourcesLayer.js.map +1 -0
  304. package/dist/features/paths/index.js +2 -2
  305. package/dist/features/paths/pathEditExtension.js.map +1 -1
  306. package/dist/features/paths/pathEditState.js +5 -2
  307. package/dist/features/paths/pathEditState.js.map +1 -1
  308. package/dist/features/paths/pathSnap/pathSnapSource.js +5 -5
  309. package/dist/features/paths/pathSnap/pathSnapSource.js.map +1 -1
  310. package/dist/features/paths/pathSnap/sceneIndex.js +10 -3
  311. package/dist/features/paths/pathSnap/sceneIndex.js.map +1 -1
  312. package/dist/features/selection/selectionPose.js +4 -1
  313. package/dist/features/selection/selectionPose.js.map +1 -1
  314. package/dist/features/snap/gather.js +9 -1
  315. package/dist/features/snap/gather.js.map +1 -1
  316. package/dist/features/snap/lazySession.js +17 -0
  317. package/dist/features/snap/lazySession.js.map +1 -0
  318. package/dist/features/snap/marks.js.map +1 -1
  319. package/dist/features/snap/probes2d.js +27 -19
  320. package/dist/features/snap/probes2d.js.map +1 -1
  321. package/dist/features/snap/readoutLayer.js.map +1 -1
  322. package/dist/features/snap/roles.js +2 -1
  323. package/dist/features/snap/roles.js.map +1 -1
  324. package/dist/features/snap/rotationSource.js +25 -8
  325. package/dist/features/snap/rotationSource.js.map +1 -1
  326. package/dist/features/snap/sceneSession2d.js +6 -4
  327. package/dist/features/snap/sceneSession2d.js.map +1 -1
  328. package/dist/features/snap/session2d.js +37 -23
  329. package/dist/features/snap/session2d.js.map +1 -1
  330. package/dist/features/snap/spanSnap.js +5 -2
  331. package/dist/features/snap/spanSnap.js.map +1 -1
  332. package/dist/features/text/sceneTextDrafts.js +65 -0
  333. package/dist/features/text/sceneTextDrafts.js.map +1 -0
  334. package/dist/features/text/textHitAt.js +31 -2
  335. package/dist/features/text/textHitAt.js.map +1 -1
  336. package/dist/features/text/useSceneTextEdit.js +22 -18
  337. package/dist/features/text/useSceneTextEdit.js.map +1 -1
  338. package/dist/features/viewports/aim.js +105 -0
  339. package/dist/features/viewports/aim.js.map +1 -0
  340. package/dist/features/viewports/viewMarker.js +82 -0
  341. package/dist/features/viewports/viewMarker.js.map +1 -0
  342. package/dist/features/viewports/viewMarkerDrag.js +55 -0
  343. package/dist/features/viewports/viewMarkerDrag.js.map +1 -0
  344. package/dist/icons.table.js +1 -1
  345. package/dist/icons.table.js.map +1 -1
  346. package/dist/icons.table.json +0 -10
  347. package/dist/index.d.ts +1198 -894
  348. package/dist/index.js +55 -38
  349. package/dist/interactions/actions/align/action.js +6 -4
  350. package/dist/interactions/actions/align/action.js.map +1 -1
  351. package/dist/interactions/actions/align/align.js.map +1 -1
  352. package/dist/interactions/actions/booleans/action.js +7 -1
  353. package/dist/interactions/actions/booleans/action.js.map +1 -1
  354. package/dist/interactions/actions/booleans/booleans.js +2 -1
  355. package/dist/interactions/actions/booleans/booleans.js.map +1 -1
  356. package/dist/interactions/actions/booleans/operands.js +6 -5
  357. package/dist/interactions/actions/booleans/operands.js.map +1 -1
  358. package/dist/interactions/actions/clipboard/action.js +27 -17
  359. package/dist/interactions/actions/clipboard/action.js.map +1 -1
  360. package/dist/interactions/actions/clone/action.js +1 -1
  361. package/dist/interactions/actions/clone/behaviors.js +4 -4
  362. package/dist/interactions/actions/clone/behaviors.js.map +1 -1
  363. package/dist/interactions/actions/defaults/anchorEditing.js +44 -23
  364. package/dist/interactions/actions/defaults/anchorEditing.js.map +1 -1
  365. package/dist/interactions/actions/defaults/anchorJoin.js +12 -6
  366. package/dist/interactions/actions/defaults/anchorJoin.js.map +1 -1
  367. package/dist/interactions/actions/defaults/bendSegment.js +8 -5
  368. package/dist/interactions/actions/defaults/bendSegment.js.map +1 -1
  369. package/dist/interactions/actions/defaults/cancelGesture.js +11 -8
  370. package/dist/interactions/actions/defaults/cancelGesture.js.map +1 -1
  371. package/dist/interactions/actions/defaults/contextMenu.js +17 -8
  372. package/dist/interactions/actions/defaults/contextMenu.js.map +1 -1
  373. package/dist/interactions/actions/defaults/createPaintAction.js +2 -2
  374. package/dist/interactions/actions/defaults/createPaintAction.js.map +1 -1
  375. package/dist/interactions/actions/defaults/delete.js +64 -41
  376. package/dist/interactions/actions/defaults/delete.js.map +1 -1
  377. package/dist/interactions/actions/defaults/duplicate.js +12 -9
  378. package/dist/interactions/actions/defaults/duplicate.js.map +1 -1
  379. package/dist/interactions/actions/defaults/enterPathEdit.js +19 -9
  380. package/dist/interactions/actions/defaults/enterPathEdit.js.map +1 -1
  381. package/dist/interactions/actions/defaults/escape.js +11 -8
  382. package/dist/interactions/actions/defaults/escape.js.map +1 -1
  383. package/dist/interactions/actions/defaults/exitPathEdit.js +7 -4
  384. package/dist/interactions/actions/defaults/exitPathEdit.js.map +1 -1
  385. package/dist/interactions/actions/defaults/group.js +21 -15
  386. package/dist/interactions/actions/defaults/group.js.map +1 -1
  387. package/dist/interactions/actions/defaults/ingest.js +17 -9
  388. package/dist/interactions/actions/defaults/ingest.js.map +1 -1
  389. package/dist/interactions/actions/defaults/insertPathAnchor.js +7 -4
  390. package/dist/interactions/actions/defaults/insertPathAnchor.js.map +1 -1
  391. package/dist/interactions/actions/defaults/nudge.js +21 -40
  392. package/dist/interactions/actions/defaults/nudge.js.map +1 -1
  393. package/dist/interactions/actions/defaults/pathEditTools.js +11 -8
  394. package/dist/interactions/actions/defaults/pathEditTools.js.map +1 -1
  395. package/dist/interactions/actions/defaults/pinchZoom.js +7 -4
  396. package/dist/interactions/actions/defaults/pinchZoom.js.map +1 -1
  397. package/dist/interactions/actions/defaults/reorder.js +24 -6
  398. package/dist/interactions/actions/defaults/reorder.js.map +1 -1
  399. package/dist/interactions/actions/defaults/selectAll.js +8 -5
  400. package/dist/interactions/actions/defaults/selectAll.js.map +1 -1
  401. package/dist/interactions/actions/defaults/setFill.js +7 -3
  402. package/dist/interactions/actions/defaults/setFill.js.map +1 -1
  403. package/dist/interactions/actions/defaults/setFillOpacity.js +1 -1
  404. package/dist/interactions/actions/defaults/setStroke.js +12 -11
  405. package/dist/interactions/actions/defaults/setStroke.js.map +1 -1
  406. package/dist/interactions/actions/defaults/setStrokeOpacity.js +1 -1
  407. package/dist/interactions/actions/defaults/toolActivate.js +7 -1
  408. package/dist/interactions/actions/defaults/toolActivate.js.map +1 -1
  409. package/dist/interactions/actions/defaults/toolResetToDefault.js +7 -4
  410. package/dist/interactions/actions/defaults/toolResetToDefault.js.map +1 -1
  411. package/dist/interactions/actions/defaults/undoRedo.js +19 -13
  412. package/dist/interactions/actions/defaults/undoRedo.js.map +1 -1
  413. package/dist/interactions/actions/defaults/viewportWheelPan.js +16 -7
  414. package/dist/interactions/actions/defaults/viewportWheelPan.js.map +1 -1
  415. package/dist/interactions/actions/defaults/viewportZoom.js +24 -6
  416. package/dist/interactions/actions/defaults/viewportZoom.js.map +1 -1
  417. package/dist/interactions/actions/distribute/action.js +6 -4
  418. package/dist/interactions/actions/distribute/action.js.map +1 -1
  419. package/dist/interactions/actions/drawnBoxes.js +2 -1
  420. package/dist/interactions/actions/drawnBoxes.js.map +1 -1
  421. package/dist/interactions/actions/edit-anchors/action.js +10 -10
  422. package/dist/interactions/actions/edit-anchors/action.js.map +1 -1
  423. package/dist/interactions/actions/edit-anchors/preview.js +41 -8
  424. package/dist/interactions/actions/edit-anchors/preview.js.map +1 -1
  425. package/dist/interactions/actions/flip/action.js +14 -6
  426. package/dist/interactions/actions/flip/action.js.map +1 -1
  427. package/dist/interactions/actions/gestureLifecycle.js +5 -2
  428. package/dist/interactions/actions/gestureLifecycle.js.map +1 -1
  429. package/dist/interactions/actions/insert/action.js +1 -2
  430. package/dist/interactions/actions/insert/action.js.map +1 -1
  431. package/dist/interactions/actions/insert/commit.js +1 -1
  432. package/dist/interactions/actions/insert/parent.js +11 -0
  433. package/dist/interactions/actions/insert/parent.js.map +1 -0
  434. package/dist/interactions/actions/insert/placeAction.js +7 -2
  435. package/dist/interactions/actions/insert/placeAction.js.map +1 -1
  436. package/dist/interactions/actions/insert/repositionAction.js +2 -1
  437. package/dist/interactions/actions/insert/repositionAction.js.map +1 -1
  438. package/dist/interactions/actions/insert/session.js +5 -1
  439. package/dist/interactions/actions/insert/session.js.map +1 -1
  440. package/dist/interactions/actions/move/action.js +15 -8
  441. package/dist/interactions/actions/move/action.js.map +1 -1
  442. package/dist/interactions/actions/move/behaviors/layoutDrop.js +0 -1
  443. package/dist/interactions/actions/move/behaviors/layoutDrop.js.map +1 -1
  444. package/dist/interactions/actions/move/behaviors/snapToContainer.js +1 -1
  445. package/dist/interactions/actions/move/capture.js +1 -1
  446. package/dist/interactions/actions/move/commit/index.js +0 -2
  447. package/dist/interactions/actions/move/commit/index.js.map +1 -1
  448. package/dist/interactions/actions/move/commit/layoutDrop.js +2 -2
  449. package/dist/interactions/actions/move/commit/layoutRelease.js +2 -2
  450. package/dist/interactions/actions/move/commit/reparent.js +11 -5
  451. package/dist/interactions/actions/move/commit/reparent.js.map +1 -1
  452. package/dist/interactions/actions/move/frame.js +4 -10
  453. package/dist/interactions/actions/move/frame.js.map +1 -1
  454. package/dist/interactions/actions/move/landedDescendants.js +20 -17
  455. package/dist/interactions/actions/move/landedDescendants.js.map +1 -1
  456. package/dist/interactions/actions/move/layout/container.js +2 -1
  457. package/dist/interactions/actions/move/layout/container.js.map +1 -1
  458. package/dist/interactions/actions/move/layout/dragged.js +1 -1
  459. package/dist/interactions/actions/move/layout/dropPass.js +18 -1
  460. package/dist/interactions/actions/move/layout/dropPass.js.map +1 -1
  461. package/dist/interactions/actions/move/layout/exits.js +5 -5
  462. package/dist/interactions/actions/move/layout/exits.js.map +1 -1
  463. package/dist/interactions/actions/move/session.js +14 -3
  464. package/dist/interactions/actions/move/session.js.map +1 -1
  465. package/dist/interactions/actions/move/translate.js +8 -37
  466. package/dist/interactions/actions/move/translate.js.map +1 -1
  467. package/dist/interactions/actions/moveNodes.js +87 -0
  468. package/dist/interactions/actions/moveNodes.js.map +1 -0
  469. package/dist/interactions/actions/outlines/createOutlinesAction.js +8 -5
  470. package/dist/interactions/actions/outlines/createOutlinesAction.js.map +1 -1
  471. package/dist/interactions/actions/outlines/outlineStroke.js +5 -3
  472. package/dist/interactions/actions/outlines/outlineStroke.js.map +1 -1
  473. package/dist/interactions/actions/pathCommands/cutJoin.js +8 -5
  474. package/dist/interactions/actions/pathCommands/cutJoin.js.map +1 -1
  475. package/dist/interactions/actions/planeInput.js.map +1 -1
  476. package/dist/interactions/actions/resize/action.js +83 -72
  477. package/dist/interactions/actions/resize/action.js.map +1 -1
  478. package/dist/interactions/actions/resize/commit.js +2 -1
  479. package/dist/interactions/actions/resize/commit.js.map +1 -1
  480. package/dist/interactions/actions/resize/cornerHandles.js +2 -1
  481. package/dist/interactions/actions/resize/cornerHandles.js.map +1 -1
  482. package/dist/interactions/actions/resize/session.js +2 -0
  483. package/dist/interactions/actions/resize/session.js.map +1 -1
  484. package/dist/interactions/actions/resolvePreviews.js +3 -3
  485. package/dist/interactions/actions/resolvePreviews.js.map +1 -1
  486. package/dist/interactions/actions/rotate/action.js +7 -4
  487. package/dist/interactions/actions/rotate/action.js.map +1 -1
  488. package/dist/interactions/actions/rotate/commit.js +2 -1
  489. package/dist/interactions/actions/rotate/commit.js.map +1 -1
  490. package/dist/interactions/actions/rotate/session.js +2 -0
  491. package/dist/interactions/actions/rotate/session.js.map +1 -1
  492. package/dist/interactions/actions/selectionSubtree.js +25 -9
  493. package/dist/interactions/actions/selectionSubtree.js.map +1 -1
  494. package/dist/interactions/actions/testUtils.js.map +1 -1
  495. package/dist/interactions/actions/transform-again/action.js +13 -11
  496. package/dist/interactions/actions/transform-again/action.js.map +1 -1
  497. package/dist/interactions/actions/transformFinish.js +106 -0
  498. package/dist/interactions/actions/transformFinish.js.map +1 -0
  499. package/dist/json.d.ts +4 -0
  500. package/dist/json.js +3 -0
  501. package/dist/kitSettingsSchema.js +8 -5
  502. package/dist/kitSettingsSchema.js.map +1 -1
  503. package/dist/{math-CrJULaZI.d.ts → math-B56zxVs5.d.ts} +10 -1
  504. package/dist/math.d.ts +1 -1
  505. package/dist/math.js +2 -1
  506. package/dist/move.d.ts +5 -4
  507. package/dist/{options-p9GZMXbY.d.ts → options-DBxEryYq.d.ts} +1 -1
  508. package/dist/resize.d.ts +4 -3
  509. package/dist/routing.d.ts +1 -1
  510. package/dist/routing.js +2 -2
  511. package/dist/test-hook/createTestHook.js +1 -1
  512. package/dist/test-hook/createTestHook.js.map +1 -1
  513. package/dist/test-hook/useTestHook.js +2 -1
  514. package/dist/test-hook/useTestHook.js.map +1 -1
  515. package/dist/test-seams.d.ts +9 -5
  516. package/dist/tools/builtin/ellipse/useEllipseTool.js +1 -0
  517. package/dist/tools/builtin/ellipse/useEllipseTool.js.map +1 -1
  518. package/dist/tools/builtin/eyedropper/useEyedropperTool.js +2 -1
  519. package/dist/tools/builtin/eyedropper/useEyedropperTool.js.map +1 -1
  520. package/dist/tools/builtin/hand/dragPanContribution.js +4 -1
  521. package/dist/tools/builtin/hand/dragPanContribution.js.map +1 -1
  522. package/dist/tools/builtin/hand/useHandTool.js +7 -4
  523. package/dist/tools/builtin/hand/useHandTool.js.map +1 -1
  524. package/dist/tools/builtin/image/useImageTool.js +1 -0
  525. package/dist/tools/builtin/image/useImageTool.js.map +1 -1
  526. package/dist/tools/builtin/lasso/useLassoTool.js +1 -0
  527. package/dist/tools/builtin/lasso/useLassoTool.js.map +1 -1
  528. package/dist/tools/builtin/line/useLineTool.js +1 -0
  529. package/dist/tools/builtin/line/useLineTool.js.map +1 -1
  530. package/dist/tools/builtin/measure/useMeasureTool.js +12 -5
  531. package/dist/tools/builtin/measure/useMeasureTool.js.map +1 -1
  532. package/dist/tools/builtin/pen/penHandle.js +3 -5
  533. package/dist/tools/builtin/pen/penHandle.js.map +1 -1
  534. package/dist/tools/builtin/pen/usePenTool.js +14 -6
  535. package/dist/tools/builtin/pen/usePenTool.js.map +1 -1
  536. package/dist/tools/builtin/pencil/usePencilTool.js +1 -0
  537. package/dist/tools/builtin/pencil/usePencilTool.js.map +1 -1
  538. package/dist/tools/builtin/polygon/usePolygonTool.js +13 -4
  539. package/dist/tools/builtin/polygon/usePolygonTool.js.map +1 -1
  540. package/dist/tools/builtin/rect/useRectTool.js +1 -0
  541. package/dist/tools/builtin/rect/useRectTool.js.map +1 -1
  542. package/dist/tools/builtin/select/adapterPointQuery.js +3 -2
  543. package/dist/tools/builtin/select/adapterPointQuery.js.map +1 -1
  544. package/dist/tools/builtin/select/pressDecision.js +32 -0
  545. package/dist/tools/builtin/select/pressDecision.js.map +1 -0
  546. package/dist/tools/builtin/select/selectionContributions.js +22 -13
  547. package/dist/tools/builtin/select/selectionContributions.js.map +1 -1
  548. package/dist/tools/builtin/select/useSelectTool.js +13 -10
  549. package/dist/tools/builtin/select/useSelectTool.js.map +1 -1
  550. package/dist/tools/builtin/slice/useSliceTool.js +22 -8
  551. package/dist/tools/builtin/slice/useSliceTool.js.map +1 -1
  552. package/dist/tools/builtin/star/useStarTool.js +13 -4
  553. package/dist/tools/builtin/star/useStarTool.js.map +1 -1
  554. package/dist/tools/builtin/sticky/stickyNode.js +4 -1
  555. package/dist/tools/builtin/sticky/stickyNode.js.map +1 -1
  556. package/dist/tools/builtin/sticky/useStickyTool.js +10 -5
  557. package/dist/tools/builtin/sticky/useStickyTool.js.map +1 -1
  558. package/dist/tools/builtin/text/useTextTool.js +3 -1
  559. package/dist/tools/builtin/text/useTextTool.js.map +1 -1
  560. package/dist/tools/index.js +26 -0
  561. package/dist/{types-CHVXGfYm.d.ts → types-7puAuVD2.d.ts} +3 -262
  562. package/dist/types-BN9hbdMI.d.ts +184 -0
  563. package/dist/types-CniVctmk.d.ts +949 -0
  564. package/dist/types-oFeQ5VjV.d.ts +264 -0
  565. package/dist/util/paint.js +1 -3
  566. package/dist/util/paint.js.map +1 -1
  567. package/dist/version.js +1 -1
  568. package/package.json +39 -25
  569. package/dist/canvas/SceneCanvas/useBuiltinRigTools.js +0 -65
  570. package/dist/canvas/SceneCanvas/useBuiltinRigTools.js.map +0 -1
  571. package/dist/tools/builtin/bone/boneActions.js +0 -156
  572. package/dist/tools/builtin/bone/boneActions.js.map +0 -1
  573. package/dist/tools/builtin/bone/boneOverlay.js +0 -71
  574. package/dist/tools/builtin/bone/boneOverlay.js.map +0 -1
  575. package/dist/tools/builtin/bone/placedRig.js +0 -28
  576. package/dist/tools/builtin/bone/placedRig.js.map +0 -1
  577. package/dist/tools/builtin/bone/rigEditState.js +0 -30
  578. package/dist/tools/builtin/bone/rigEditState.js.map +0 -1
  579. package/dist/tools/builtin/bone/useBoneTool.js +0 -125
  580. package/dist/tools/builtin/bone/useBoneTool.js.map +0 -1
  581. package/dist/tools/builtin/weight/useWeightTool.js +0 -101
  582. package/dist/tools/builtin/weight/useWeightTool.js.map +0 -1
  583. package/dist/tools/builtin/weight/weightActions.js +0 -140
  584. package/dist/tools/builtin/weight/weightActions.js.map +0 -1
  585. package/dist/tools/builtin/weight/weightOverlay.js +0 -78
  586. package/dist/tools/builtin/weight/weightOverlay.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"action.js","names":[],"sources":["../../../../src/interactions/actions/flip/action.ts"],"sourcesContent":["import type { NodeId, Scene } from 'core/scene/types';\nimport type { Bounds } from 'core/viewport/fitViewToBounds';\nimport { shapeSources } from '../selectionSubtree';\nimport type { Op } from 'core/ops/types';\nimport { multiply, rotate, translate, type Affine } from '@weasel-js/geom';\nimport { createTransformOp } from 'core/ops/transform';\nimport type { PoseDescriptor } from '../resize/geometry';\nimport { poseDescriptorOf } from '../poseDescriptorDep';\nimport {\n flipPoseAboutBounds,\n flipPoseViaDescriptor,\n type FlipAxis,\n type FlipPivot,\n} from './helpers';\nimport { unionAABB } from 'core/geometry/unionBounds';\nimport { drawnBoxes, type DrawnBoxes } from '../drawnBoxes';\nimport { isNoInkExtents } from 'core/geometry/inkExtents';\nimport { scenePoseFrame, type PoseFrame } from '../poseFrame';\nimport { actionReferenceSources, resolveSpatialReference } from '../spatialReference';\nimport type { PointerContextValue } from '@weasel-js/routing/react';\nimport type { RectPose } from 'core/scene/types';\nimport type { Action } from '@weasel-js/routing';\nimport { defaultCommitAdapter } from '../defaultCommitAdapter';\nimport { requiresSelection } from '../defaults/requiresSelection';\nimport type { SelectionApi } from 'core/selection/useSelection';\nimport { geometryDataOp, type GeometryProjection } from '../geometryProjection';\nimport { icon } from '../../../icons.gen';\n\n/**\n * The world mirror about `axis` through the center of `pivotWorld`, written in\n * the frame `id` stores its data in. `geometryProjection.transform` is given\n * the affine the node's own pose underwent, and data-held geometry is local —\n * so a world mirror has to be conjugated by the frame or an asymmetric shape\n * reflects across the wrong line while its pose lands correctly.\n *\n * The frame's turn comes back as the rotation on a rebased zero-size pose at\n * the pivot point, so no composition strategy has to expose one.\n */\nfunction localMirror(\n axis: FlipAxis,\n frame: PoseFrame<unknown>,\n id: Parameters<PoseFrame<unknown>['local']>[0],\n pivotWorld: { x: number; y: number; width: number; height: number },\n): Affine {\n const at = frame.local(id, {\n x: pivotWorld.x + pivotWorld.width / 2,\n y: pivotWorld.y + pivotWorld.height / 2,\n width: 0,\n height: 0,\n rotation: 0,\n }) as RectPose;\n const theta = at.rotation ?? 0;\n const mirror: Affine = axis === 'x' ? [-1, 0, 0, 1, 0, 0] : [1, 0, 0, -1, 0, 0];\n const turned = multiply(multiply(rotate(theta), mirror), rotate(-theta));\n return multiply(translate(at.x, at.y), multiply(turned, translate(-at.x, -at.y)));\n}\n\n/**\n * Flip the current selection in `scene` along `axis`, as one undo entry.\n *\n * Pivot: `'each'` (per-item own AABB) unless the caller passes `'union'`,\n * which mirrors every pose about the selection's *visual* union AABB — the\n * rotated ink extents — so items swap sides as well as reflect, or a\n * `SpatialReference`, which mirrors about the center of what it names. A rotated\n * member's own mirrored position needs no expansion: `axisAlignedBounds`\n * keeps the stored box's center, so mirroring either box lands the same place.\n */\nfunction flipSelection(\n selection: SelectionApi,\n scene: Scene<unknown, string, unknown>,\n axis: FlipAxis,\n pivot: FlipPivot,\n applyOps: ((ops: Op[], label: string) => void) | undefined,\n geometryProjection: GeometryProjection | undefined,\n geom: PoseDescriptor<unknown>,\n params: Record<string, unknown> | undefined,\n pointer: PointerContextValue | undefined,\n boxesOver: (frame: PoseFrame<unknown>) => DrawnBoxes,\n): void {\n const selected = selection.get();\n if (selected.length === 0) return;\n const frame = scenePoseFrame(scene);\n const boxes = boxesOver(frame);\n\n // A group whose pose derives from its children mirrors by mirroring them,\n // about the group's own box where each selected node flips in place.\n const ids: NodeId[] = [];\n const ownPivot = new Map<string, Bounds>();\n for (const id of selected) {\n const members = shapeSources(scene, [id]) as NodeId[];\n const stoodIn = members.length !== 1 || members[0] !== id;\n const box = stoodIn ? boxes.aabb(id, frame.world(id)) : null;\n for (const member of members) {\n if (ids.includes(member)) continue;\n ids.push(member);\n if (box) ownPivot.set(member, box);\n }\n }\n\n const worlds = new Map<string, unknown>();\n for (const id of ids) {\n if (scene.get(id) === undefined) continue;\n const world = frame.world(id);\n worlds.set(id as string, world);\n // A shape whose ink reaches past its box unevenly flips in place about\n // the box it is drawn with, so that box stays put.\n if (!ownPivot.has(id as string) && !isNoInkExtents(boxes.extents(id, world))) {\n ownPivot.set(id as string, boxes.aabb(id, world));\n }\n }\n let sharedPivot: ReturnType<typeof unionAABB> = null;\n if (pivot === 'union') {\n sharedPivot = unionAABB([...worlds].map(([id, p]) => boxes.aabb(id, p)));\n } else if (pivot !== 'each') {\n sharedPivot = resolveSpatialReference(pivot, actionReferenceSources(params, pointer, scene, frame, boxes));\n if (sharedPivot === null) return;\n }\n\n const ops: Op[] = [];\n for (const id of ids) {\n const node = scene.get(id);\n if (!node) continue;\n const world = worlds.get(id as string)!;\n const about = sharedPivot ?? ownPivot.get(id as string) ?? null;\n const flipped = about\n ? flipPoseAboutBounds(world, axis, geom, about)\n : flipPoseViaDescriptor(world, axis, geom);\n ops.push(createTransformOp<unknown>({\n id: id as string,\n from: node.pose,\n to: frame.local(id, flipped),\n label: 'Flip',\n }));\n // Mirror the data-held geometry about the SAME pivot the pose flip uses.\n // A pose-only flip of a bare-AABB pose is identity, so this data op is\n // the only way an asymmetric shape actually mirrors.\n const g = about ?? geom.getBounds(world);\n const dataOp = geometryDataOp(\n geometryProjection,\n { id: id as string, data: node.data, pose: node.pose },\n localMirror(axis, frame, id, g),\n 'Flip',\n );\n if (dataOp) ops.push(dataOp);\n }\n if (ops.length === 0) return;\n\n if (applyOps) applyOps(ops, 'Flip');\n else scene.applyBatch(ops, 'Flip', defaultCommitAdapter(scene, selection.adapterMethods));\n}\n\n/**\n * Flips the selection. `params.axis` (`'x'` | `'y'`, default `'x'`) picks the\n * direction, and the optional `params.pivot` (a `FlipPivot`, default `'each'`)\n * picks what it mirrors about.\n */\nexport const flipAction: Action & { requires: string[] } = {\n id: 'flip',\n label: 'Flip',\n group: 'flip',\n tags: ['mirror'],\n variants: [\n { key: 'x', label: 'Flip Horizontal', icon: icon('flipX'), params: { axis: 'x' } },\n { key: 'y', label: 'Flip Vertical', icon: icon('flipY'), params: { axis: 'y' } },\n ],\n defaultBinding: [\n { spec: { kind: 'key', key: ['h', 'H'], mods: { shift: true } }, opts: { params: { axis: 'x' } } },\n { spec: { kind: 'key', key: ['v', 'V'], mods: { shift: true } }, opts: { params: { axis: 'y' } } },\n ],\n eligible: { capability: 'transforms-selection' },\n requires: ['selection', 'scene', 'applyOps', 'geometryProjection', 'poseDescriptor', 'pointer', 'view', 'boundsIncludeStroke'],\n invoker: {\n timing: 'immediate',\n run: (deps, params) => {\n const axis = (params?.axis as FlipAxis | undefined) ?? 'x';\n const pivot = (params?.pivot as FlipPivot | undefined) ?? 'each';\n const selection = deps.selection;\n const scene = deps.scene;\n const applyOps = deps.applyOps;\n const geometryProjection = deps.geometryProjection;\n if (!selection || !scene) return;\n flipSelection(\n selection, scene, axis, pivot, applyOps, geometryProjection,\n poseDescriptorOf(deps.poseDescriptor),\n params, deps.pointer,\n (frame) => drawnBoxes(deps, frame),\n );\n },\n },\n enabled: requiresSelection,\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"action.js","names":[],"sources":["../../../../src/interactions/actions/flip/action.ts"],"sourcesContent":["import type { NodeId, Scene } from 'core/scene/types';\nimport type { Bounds } from 'core/viewport/fitViewToBounds';\nimport { shapeSources } from '../selectionSubtree';\nimport type { Op } from 'core/ops/types';\nimport { multiply, rotate, translate, type Affine } from '@weasel-js/geom';\nimport { createTransformOp } from 'core/ops/transform';\nimport type { PoseDescriptor } from '../resize/geometry';\nimport { poseDescriptorOf } from '../poseDescriptorDep';\nimport {\n flipPoseAboutBounds,\n flipPoseViaDescriptor,\n type FlipAxis,\n type FlipPivot,\n} from './helpers';\nimport { unionAABB } from 'core/geometry/unionBounds';\nimport { drawnBoxes, type DrawnBoxes } from '../drawnBoxes';\nimport { isNoInkExtents } from 'core/geometry/inkExtents';\nimport { scenePoseFrame, type PoseFrame } from '../poseFrame';\nimport { actionReferenceSources, resolveSpatialReference } from '../spatialReference';\nimport type { PointerContextValue } from '@weasel-js/routing/react';\nimport type { RectPose } from 'core/scene/types';\nimport type { Action } from '@weasel-js/routing';\nimport { defaultCommitAdapter } from '../defaultCommitAdapter';\nimport { transformApplyOps } from '../transformFinish';\nimport { requiresSelection } from '../defaults/requiresSelection';\nimport type { SelectionApi } from 'core/selection/useSelection';\nimport { geometryDataOp, type GeometryProjection } from '../geometryProjection';\nimport { icon } from '../../../icons.gen';\n\n/**\n * The world mirror about `axis` through the center of `pivotWorld`, written in\n * the frame `id` stores its data in. `geometryProjection.transform` is given\n * the affine the node's own pose underwent, and data-held geometry is local —\n * so a world mirror has to be conjugated by the frame or an asymmetric shape\n * reflects across the wrong line while its pose lands correctly.\n *\n * The frame's turn comes back as the rotation on a rebased zero-size pose at\n * the pivot point, so no composition strategy has to expose one.\n */\nfunction localMirror(\n axis: FlipAxis,\n frame: PoseFrame<unknown>,\n id: Parameters<PoseFrame<unknown>['local']>[0],\n pivotWorld: { x: number; y: number; width: number; height: number },\n): Affine {\n const at = frame.local(id, {\n x: pivotWorld.x + pivotWorld.width / 2,\n y: pivotWorld.y + pivotWorld.height / 2,\n width: 0,\n height: 0,\n rotation: 0,\n }) as RectPose;\n const theta = at.rotation ?? 0;\n const mirror: Affine = axis === 'x' ? [-1, 0, 0, 1, 0, 0] : [1, 0, 0, -1, 0, 0];\n const turned = multiply(multiply(rotate(theta), mirror), rotate(-theta));\n return multiply(translate(at.x, at.y), multiply(turned, translate(-at.x, -at.y)));\n}\n\n/**\n * Flip the current selection in `scene` along `axis`, as one undo entry.\n *\n * Pivot: `'each'` (per-item own AABB) unless the caller passes `'union'`,\n * which mirrors every pose about the selection's *visual* union AABB — the\n * rotated ink extents — so items swap sides as well as reflect, or a\n * `SpatialReference`, which mirrors about the center of what it names. A rotated\n * member's own mirrored position needs no expansion: `axisAlignedBounds`\n * keeps the stored box's center, so mirroring either box lands the same place.\n */\nfunction flipSelection(\n selection: SelectionApi,\n scene: Scene<unknown, string, unknown>,\n axis: FlipAxis,\n pivot: FlipPivot,\n applyOps: ((ops: Op[], label: string) => void) | undefined,\n geometryProjection: GeometryProjection | undefined,\n geom: PoseDescriptor<unknown>,\n params: Record<string, unknown> | undefined,\n pointer: PointerContextValue | undefined,\n boxesOver: (frame: PoseFrame<unknown>) => DrawnBoxes,\n): void {\n const selected = selection.get();\n if (selected.length === 0) return;\n const frame = scenePoseFrame(scene);\n const boxes = boxesOver(frame);\n\n // A group whose pose derives from its children mirrors by mirroring them,\n // about the group's own box where each selected node flips in place.\n const ids: NodeId[] = [];\n const ownPivot = new Map<string, Bounds>();\n for (const id of selected) {\n const members = shapeSources(scene, [id]) as NodeId[];\n const stoodIn = members.length !== 1 || members[0] !== id;\n const box = stoodIn ? boxes.aabb(id, frame.world(id)) : null;\n for (const member of members) {\n if (ids.includes(member)) continue;\n ids.push(member);\n if (box) ownPivot.set(member, box);\n }\n }\n\n const worlds = new Map<string, unknown>();\n for (const id of ids) {\n if (scene.get(id) === undefined) continue;\n const world = frame.world(id);\n worlds.set(id as string, world);\n // A shape whose ink reaches past its box unevenly flips in place about\n // the box it is drawn with, so that box stays put.\n if (!ownPivot.has(id as string) && !isNoInkExtents(boxes.extents(id, world))) {\n ownPivot.set(id as string, boxes.aabb(id, world));\n }\n }\n let sharedPivot: ReturnType<typeof unionAABB> = null;\n if (pivot === 'union') {\n sharedPivot = unionAABB([...worlds].map(([id, p]) => boxes.aabb(id, p)));\n } else if (pivot !== 'each') {\n sharedPivot = resolveSpatialReference(pivot, actionReferenceSources(params, pointer, scene, frame, boxes));\n if (sharedPivot === null) return;\n }\n\n const ops: Op[] = [];\n for (const id of ids) {\n const node = scene.get(id);\n if (!node) continue;\n const world = worlds.get(id as string)!;\n const about = sharedPivot ?? ownPivot.get(id as string) ?? null;\n const flipped = about\n ? flipPoseAboutBounds(world, axis, geom, about)\n : flipPoseViaDescriptor(world, axis, geom);\n ops.push(createTransformOp<unknown>({\n id: id as string,\n from: node.pose,\n to: frame.local(id, flipped),\n label: 'Flip',\n }));\n // Mirror the data-held geometry about the SAME pivot the pose flip uses.\n // A pose-only flip of a bare-AABB pose is identity, so this data op is\n // the only way an asymmetric shape actually mirrors.\n const g = about ?? geom.getBounds(world);\n const dataOp = geometryDataOp(\n geometryProjection,\n { id: id as string, data: node.data, pose: node.pose },\n localMirror(axis, frame, id, g),\n 'Flip',\n );\n if (dataOp) ops.push(dataOp);\n }\n if (ops.length === 0) return;\n\n if (applyOps) applyOps(ops, 'Flip');\n else scene.applyBatch(ops, 'Flip', defaultCommitAdapter(scene, selection.adapterMethods));\n}\n\n/**\n * Flips the selection. `params.axis` (`'x'` | `'y'`, default `'x'`) picks the\n * direction, and the optional `params.pivot` (a `FlipPivot`, default `'each'`)\n * picks what it mirrors about.\n */\nexport const flipAction: Action & { requires: string[] } = {\n id: 'flip',\n label: 'Flip',\n group: 'flip',\n tags: ['mirror'],\n variants: [\n { key: 'x', label: 'Flip Horizontal', icon: icon('flipX'), params: { axis: 'x' } },\n { key: 'y', label: 'Flip Vertical', icon: icon('flipY'), params: { axis: 'y' } },\n ],\n defaultBinding: [\n { spec: { kind: 'key', key: ['h', 'H'], mods: { shift: true } }, opts: { id: 'flip.x', params: { axis: 'x' } } },\n { spec: { kind: 'key', key: ['v', 'V'], mods: { shift: true } }, opts: { id: 'flip.y', params: { axis: 'y' } } },\n ],\n eligible: { capability: 'transforms-selection' },\n requires: [\n 'selection', 'scene', 'applyOps', 'geometryProjection', 'poseDescriptor', 'pointer', 'view', 'boundsIncludeStroke',\n 'transformFollowers',\n ],\n invoker: {\n timing: 'immediate',\n run: (deps, params) => {\n const axis = (params?.axis as FlipAxis | undefined) ?? 'x';\n const pivot = (params?.pivot as FlipPivot | undefined) ?? 'each';\n const selection = deps.selection;\n const scene = deps.scene;\n const applyOps = transformApplyOps(deps);\n const geometryProjection = deps.geometryProjection;\n if (!selection || !scene) return;\n flipSelection(\n selection, scene, axis, pivot, applyOps, geometryProjection,\n poseDescriptorOf(deps.poseDescriptor),\n params, deps.pointer,\n (frame) => drawnBoxes(deps, frame),\n );\n },\n },\n enabled: requiresSelection,\n};\n"],"mappings":"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"}
@@ -31,12 +31,15 @@ function readGestureLifecycle(source, defaultLabel, behaviors = []) {
31
31
  }
32
32
  };
33
33
  }
34
- /** Commit a gesture's ops: untracked when transient, else through the
34
+ /** Commit a gesture's ops, finished by `target.finish` when it has one:
35
+ * untracked when transient, else through the
35
36
  * consumer `applyOps` hook when one is wired, else into the scene's history.
36
37
  * Returns whether the commit landed: false when a container refused what
37
38
  * the ops brought it, which the scene reverts. A consumer's `applyOps` may
38
39
  * keep the document elsewhere, so it is taken at its word. */
39
- function commitGestureOps(target, lifecycle, ops) {
40
+ function commitGestureOps(target, lifecycle, given) {
41
+ const ops = target.finish ? target.finish(given, lifecycle.labelFor(given)) : given;
42
+ if (!ops) return false;
40
43
  if (lifecycle.transient) {
41
44
  try {
42
45
  target.scene.untracked(() => {
@@ -1 +1 @@
1
- {"version":3,"file":"gestureLifecycle.js","names":[],"sources":["../../../src/interactions/actions/gestureLifecycle.ts"],"sourcesContent":["/**\n * The lifecycle the ongoing transform actions (`move`, `resize`, `rotate`)\n * share: what their committed batch is called in history, whether it is\n * recorded at all, and the callbacks fired as the gesture opens and closes.\n *\n * Move and rotate read it from their binding's params; resize reads it from\n * the `resizePolicy` dep, where the rest of its options already live.\n */\nimport type { Op } from 'core/ops/types';\nimport { SceneArrivalRefused } from 'core/scene/arrivals';\nimport type { Scene } from 'core/scene/types';\nimport type { BehaviorEnd } from 'interactions/gestures/types';\nimport type { NodeId, PoseHold } from 'core/scene/types';\n\n/** The lifecycle options, as a binding's params or the resize policy carry\n * them. */\nexport interface GestureLifecycleOptions {\n /** History label for the committed batch. Unset, the batch takes its first\n * op's label (a layout drop or a behavior names its own), else the\n * action's. */\n label?: string;\n /** Commit through `scene.untracked`: the edit lands, but no undo entry\n * records it and the consumer `applyOps` hook is bypassed. Unset, any\n * behavior's `defaultTransient: true` turns it on. */\n transient?: boolean;\n /** Fired once the gesture starts changing poses, with the ids it moves. */\n onGestureStart?(ids: string[]): void;\n /** Fired once per `onGestureStart`: `true` when the gesture wrote to the\n * document, `false` on cancel, abort, or a release with nothing to write. */\n onGestureEnd?(committed: boolean): void;\n}\n\n/** The params entries for {@link GestureLifecycleOptions}, with the unset\n * keys left out. */\nexport function gestureLifecycleParams(o: GestureLifecycleOptions): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n if (o.label !== undefined) out.label = o.label;\n if (o.transient !== undefined) out.transient = o.transient;\n if (o.onGestureStart) out.onGestureStart = o.onGestureStart;\n if (o.onGestureEnd) out.onGestureEnd = o.onGestureEnd;\n return out;\n}\n\n/** A gesture's resolved lifecycle. `start` and `end` fire their callbacks at\n * most once each, and `end` only after `start`. */\nexport interface GestureLifecycle {\n /** The label ops built by the action itself carry. */\n readonly label: string;\n /** The history label for committing `ops`. */\n labelFor(ops: readonly Op[]): string;\n readonly transient: boolean;\n start(ids: readonly string[]): void;\n end(committed: boolean): void;\n}\n\nexport function readGestureLifecycle(\n source: GestureLifecycleOptions | Record<string, unknown> | undefined,\n defaultLabel: string,\n behaviors: readonly { defaultTransient?: boolean }[] = [],\n): GestureLifecycle {\n const o = (source ?? {}) as GestureLifecycleOptions;\n let started = false;\n let ended = false;\n return {\n label: o.label ?? defaultLabel,\n labelFor: (ops) => o.label ?? ops[0]?.label ?? defaultLabel,\n transient: o.transient ?? behaviors.some((b) => b.defaultTransient === true),\n start(ids) {\n if (started) return;\n started = true;\n o.onGestureStart?.([...ids]);\n },\n end(committed) {\n if (!started || ended) return;\n ended = true;\n o.onGestureEnd?.(committed);\n },\n };\n}\n\n/** Commit a gesture's ops: untracked when transient, else through the\n * consumer `applyOps` hook when one is wired, else into the scene's history.\n * Returns whether the commit landed: false when a container refused what\n * the ops brought it, which the scene reverts. A consumer's `applyOps` may\n * keep the document elsewhere, so it is taken at its word. */\nexport function commitGestureOps(\n target: {\n scene: Scene<unknown, string, unknown>;\n applyOps?: (ops: Op[], label: string) => void;\n adapter: unknown;\n },\n lifecycle: GestureLifecycle,\n ops: Op[],\n): boolean {\n if (lifecycle.transient) {\n try {\n target.scene.untracked(() => {\n for (const op of ops) op.apply(target.adapter);\n });\n } catch (err) {\n // `untracked` lets a refused arrival out; `applyBatch` swallows it.\n if (!(err instanceof SceneArrivalRefused)) throw err;\n return false;\n }\n return true;\n }\n const label = lifecycle.labelFor(ops);\n if (!target.applyOps) return target.scene.applyBatch(ops, label, target.adapter);\n target.applyOps(ops, label);\n return true;\n}\n\n/** The trailing argument of {@link reduceBehaviorEnd}: what `TEnd` adds to\n * `BehaviorEnd`, required exactly when it adds something. */\ntype OwnEndFields<TEnd extends BehaviorEnd> = keyof Omit<TEnd, keyof BehaviorEnd> extends never\n ? [own?: Omit<TEnd, keyof BehaviorEnd>]\n : [own: Omit<TEnd, keyof BehaviorEnd>];\n\n/** Runs every behavior's `onEnd` in order; the first that answers decides the\n * commit and later answers are ignored. `null` aborts, `Op[]` claims it (an\n * empty array included), and `undefined` means every behavior deferred to the\n * action's own commit. An action whose behaviors take more than a plain\n * `BehaviorEnd` passes the rest as `own`; each `onEnd` gets it beside\n * `answered`. One that throws does not stop the rest, which are told the\n * commit is decided; its error is rethrown after, so nothing commits. */\nexport function reduceBehaviorEnd<TCtx, TEnd extends BehaviorEnd = BehaviorEnd>(\n behaviors: readonly { onEnd?(ctx: TCtx, end: TEnd): Op[] | null | void }[],\n ctx: TCtx,\n ...[own]: OwnEndFields<TEnd>\n): Op[] | null | undefined {\n let answer: Op[] | null | undefined;\n let threw = false;\n runEvery(behaviors, (b) => {\n try {\n const r = b.onEnd?.(ctx, { ...own, answered: threw || answer !== undefined } as TEnd);\n if (answer === undefined && r !== undefined) answer = r;\n } catch (err) {\n threw = true;\n throw err;\n }\n });\n return answer;\n}\n\n/** Runs `step` for every item, a throwing one included, then rethrows the\n * first error. For steps that each release something of their own. */\nfunction runEvery<T>(items: readonly T[], step: (item: T) => void): void {\n const errors: unknown[] = [];\n for (const item of items) {\n try {\n step(item);\n } catch (err) {\n errors.push(err);\n }\n }\n if (errors.length > 0) throw errors[0];\n}\n\n/** Runs every behavior's `onCancel`, for a gesture closing without a commit.\n * One that throws does not stop the rest; its error is rethrown after. */\nexport function runBehaviorCancel<TCtx>(\n behaviors: readonly { onCancel?(ctx: TCtx): void }[],\n ctx: TCtx,\n): void {\n runEvery(behaviors, (b) => b.onCancel?.(ctx));\n}\n\n/** Runs every behavior's `onSettled`, once the gesture's commit has landed or\n * its cancel has run. One that throws does not stop the rest; its error is\n * rethrown after. */\nexport function runBehaviorSettled<TCtx>(\n behaviors: readonly { onSettled?(ctx: TCtx, committed: boolean): void }[],\n ctx: TCtx,\n committed: boolean,\n): void {\n runEvery(behaviors, (b) => b.onSettled?.(ctx, committed));\n}\n\n/** What {@link closeGesture} closes. */\nexport interface ClosingGesture<TCtx> {\n hold: PoseHold<unknown>;\n /** The action's own buffer of this frame's poses, emptied at the close. */\n previews: Map<NodeId, unknown>;\n behaviors: readonly { onSettled?(ctx: TCtx, committed: boolean): void }[];\n ctx: TCtx;\n lifecycle: GestureLifecycle;\n}\n\n/**\n * The close a transform action runs from its `finally`, commit or cancel:\n * drop the preview overrides, tell the behaviors, then fire `onGestureEnd`,\n * which fires even when a behavior's `onSettled` throws; the first error is\n * rethrown.\n */\nexport function closeGesture<TCtx>(gesture: ClosingGesture<TCtx>, committed: boolean): void {\n gesture.hold.drop();\n gesture.previews.clear();\n runEvery([\n () => runBehaviorSettled(gesture.behaviors, gesture.ctx, committed),\n () => gesture.lifecycle.end(committed),\n ], (step) => step());\n}\n"],"mappings":";;;;;AAkCA,SAAgB,uBAAuB,GAAqD;CAC1F,MAAM,MAA+B,CAAC;CACtC,IAAI,EAAE,UAAU,QAAW,IAAI,QAAQ,EAAE;CACzC,IAAI,EAAE,cAAc,QAAW,IAAI,YAAY,EAAE;CACjD,IAAI,EAAE,gBAAgB,IAAI,iBAAiB,EAAE;CAC7C,IAAI,EAAE,cAAc,IAAI,eAAe,EAAE;CACzC,OAAO;AACT;AAcA,SAAgB,qBACd,QACA,cACA,YAAuD,CAAC,GACtC;CAClB,MAAM,IAAK,UAAU,CAAC;CACtB,IAAI,UAAU;CACd,IAAI,QAAQ;CACZ,OAAO;EACL,OAAO,EAAE,SAAS;EAClB,WAAW,QAAQ,EAAE,SAAS,IAAI,EAAE,EAAE,SAAS;EAC/C,WAAW,EAAE,aAAa,UAAU,MAAM,MAAM,EAAE,qBAAqB,IAAI;EAC3E,MAAM,KAAK;GACT,IAAI,SAAS;GACb,UAAU;GACV,EAAE,iBAAiB,CAAC,GAAG,GAAG,CAAC;EAC7B;EACA,IAAI,WAAW;GACb,IAAI,CAAC,WAAW,OAAO;GACvB,QAAQ;GACR,EAAE,eAAe,SAAS;EAC5B;CACF;AACF;;;;;;AAOA,SAAgB,iBACd,QAKA,WACA,KACS;CACT,IAAI,UAAU,WAAW;EACvB,IAAI;GACF,OAAO,MAAM,gBAAgB;IAC3B,KAAK,MAAM,MAAM,KAAK,GAAG,MAAM,OAAO,OAAO;GAC/C,CAAC;EACH,SAAS,KAAK;GAEZ,IAAI,EAAE,eAAe,sBAAsB,MAAM;GACjD,OAAO;EACT;EACA,OAAO;CACT;CACA,MAAM,QAAQ,UAAU,SAAS,GAAG;CACpC,IAAI,CAAC,OAAO,UAAU,OAAO,OAAO,MAAM,WAAW,KAAK,OAAO,OAAO,OAAO;CAC/E,OAAO,SAAS,KAAK,KAAK;CAC1B,OAAO;AACT;;;;;;;;AAeA,SAAgB,kBACd,WACA,KACA,GAAG,CAAC,MACqB;CACzB,IAAI;CACJ,IAAI,QAAQ;CACZ,SAAS,YAAY,MAAM;EACzB,IAAI;GACF,MAAM,IAAI,EAAE,QAAQ,KAAK;IAAE,GAAG;IAAK,UAAU,SAAS,WAAW;GAAU,CAAS;GACpF,IAAI,WAAW,UAAa,MAAM,QAAW,SAAS;EACxD,SAAS,KAAK;GACZ,QAAQ;GACR,MAAM;EACR;CACF,CAAC;CACD,OAAO;AACT;;;AAIA,SAAS,SAAY,OAAqB,MAA+B;CACvE,MAAM,SAAoB,CAAC;CAC3B,KAAK,MAAM,QAAQ,OACjB,IAAI;EACF,KAAK,IAAI;CACX,SAAS,KAAK;EACZ,OAAO,KAAK,GAAG;CACjB;CAEF,IAAI,OAAO,SAAS,GAAG,MAAM,OAAO;AACtC;;;AAIA,SAAgB,kBACd,WACA,KACM;CACN,SAAS,YAAY,MAAM,EAAE,WAAW,GAAG,CAAC;AAC9C;;;;AAKA,SAAgB,mBACd,WACA,KACA,WACM;CACN,SAAS,YAAY,MAAM,EAAE,YAAY,KAAK,SAAS,CAAC;AAC1D;;;;;;;AAkBA,SAAgB,aAAmB,SAA+B,WAA0B;CAC1F,QAAQ,KAAK,KAAK;CAClB,QAAQ,SAAS,MAAM;CACvB,SAAS,OACD,mBAAmB,QAAQ,WAAW,QAAQ,KAAK,SAAS,SAC5D,QAAQ,UAAU,IAAI,SAAS,CACvC,IAAI,SAAS,KAAK,CAAC;AACrB"}
1
+ {"version":3,"file":"gestureLifecycle.js","names":[],"sources":["../../../src/interactions/actions/gestureLifecycle.ts"],"sourcesContent":["/**\n * The lifecycle the ongoing transform actions (`move`, `resize`, `rotate`)\n * share: what their committed batch is called in history, whether it is\n * recorded at all, and the callbacks fired as the gesture opens and closes.\n *\n * Move and rotate read it from their binding's params; resize reads it from\n * the `resizePolicy` dep, where the rest of its options already live.\n */\nimport type { Op } from 'core/ops/types';\nimport { SceneArrivalRefused } from 'core/scene/arrivals';\nimport type { Scene } from 'core/scene/types';\nimport type { BehaviorEnd } from 'interactions/gestures/types';\nimport type { NodeId, PoseHold } from 'core/scene/types';\nimport type { TransformFinisher } from './transformFinish';\n\n/** The lifecycle options, as a binding's params or the resize policy carry\n * them. */\nexport interface GestureLifecycleOptions {\n /** History label for the committed batch. Unset, the batch takes its first\n * op's label (a layout drop or a behavior names its own), else the\n * action's. */\n label?: string;\n /** Commit through `scene.untracked`: the edit lands, but no undo entry\n * records it and the consumer `applyOps` hook is bypassed. Unset, any\n * behavior's `defaultTransient: true` turns it on. */\n transient?: boolean;\n /** Fired once the gesture starts changing poses, with the ids it moves. */\n onGestureStart?(ids: string[]): void;\n /** Fired once per `onGestureStart`: `true` when the gesture wrote to the\n * document, `false` on cancel, abort, or a release with nothing to write. */\n onGestureEnd?(committed: boolean): void;\n}\n\n/** The params entries for {@link GestureLifecycleOptions}, with the unset\n * keys left out. */\nexport function gestureLifecycleParams(o: GestureLifecycleOptions): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n if (o.label !== undefined) out.label = o.label;\n if (o.transient !== undefined) out.transient = o.transient;\n if (o.onGestureStart) out.onGestureStart = o.onGestureStart;\n if (o.onGestureEnd) out.onGestureEnd = o.onGestureEnd;\n return out;\n}\n\n/** A gesture's resolved lifecycle. `start` and `end` fire their callbacks at\n * most once each, and `end` only after `start`. */\nexport interface GestureLifecycle {\n /** The label ops built by the action itself carry. */\n readonly label: string;\n /** The history label for committing `ops`. */\n labelFor(ops: readonly Op[]): string;\n readonly transient: boolean;\n start(ids: readonly string[]): void;\n end(committed: boolean): void;\n}\n\nexport function readGestureLifecycle(\n source: GestureLifecycleOptions | Record<string, unknown> | undefined,\n defaultLabel: string,\n behaviors: readonly { defaultTransient?: boolean }[] = [],\n): GestureLifecycle {\n const o = (source ?? {}) as GestureLifecycleOptions;\n let started = false;\n let ended = false;\n return {\n label: o.label ?? defaultLabel,\n labelFor: (ops) => o.label ?? ops[0]?.label ?? defaultLabel,\n transient: o.transient ?? behaviors.some((b) => b.defaultTransient === true),\n start(ids) {\n if (started) return;\n started = true;\n o.onGestureStart?.([...ids]);\n },\n end(committed) {\n if (!started || ended) return;\n ended = true;\n o.onGestureEnd?.(committed);\n },\n };\n}\n\n/** Commit a gesture's ops, finished by `target.finish` when it has one:\n * untracked when transient, else through the\n * consumer `applyOps` hook when one is wired, else into the scene's history.\n * Returns whether the commit landed: false when a container refused what\n * the ops brought it, which the scene reverts. A consumer's `applyOps` may\n * keep the document elsewhere, so it is taken at its word. */\nexport function commitGestureOps(\n target: {\n scene: Scene<unknown, string, unknown>;\n applyOps?: (ops: Op[], label: string) => void;\n adapter: unknown;\n finish?: TransformFinisher;\n },\n lifecycle: GestureLifecycle,\n given: Op[],\n): boolean {\n const ops = target.finish ? target.finish(given, lifecycle.labelFor(given)) : given;\n if (!ops) return false;\n if (lifecycle.transient) {\n try {\n target.scene.untracked(() => {\n for (const op of ops) op.apply(target.adapter);\n });\n } catch (err) {\n // `untracked` lets a refused arrival out; `applyBatch` swallows it.\n if (!(err instanceof SceneArrivalRefused)) throw err;\n return false;\n }\n return true;\n }\n const label = lifecycle.labelFor(ops);\n if (!target.applyOps) return target.scene.applyBatch(ops, label, target.adapter);\n target.applyOps(ops, label);\n return true;\n}\n\n/** The trailing argument of {@link reduceBehaviorEnd}: what `TEnd` adds to\n * `BehaviorEnd`, required exactly when it adds something. */\ntype OwnEndFields<TEnd extends BehaviorEnd> = keyof Omit<TEnd, keyof BehaviorEnd> extends never\n ? [own?: Omit<TEnd, keyof BehaviorEnd>]\n : [own: Omit<TEnd, keyof BehaviorEnd>];\n\n/** Runs every behavior's `onEnd` in order; the first that answers decides the\n * commit and later answers are ignored. `null` aborts, `Op[]` claims it (an\n * empty array included), and `undefined` means every behavior deferred to the\n * action's own commit. An action whose behaviors take more than a plain\n * `BehaviorEnd` passes the rest as `own`; each `onEnd` gets it beside\n * `answered`. One that throws does not stop the rest, which are told the\n * commit is decided; its error is rethrown after, so nothing commits. */\nexport function reduceBehaviorEnd<TCtx, TEnd extends BehaviorEnd = BehaviorEnd>(\n behaviors: readonly { onEnd?(ctx: TCtx, end: TEnd): Op[] | null | void }[],\n ctx: TCtx,\n ...[own]: OwnEndFields<TEnd>\n): Op[] | null | undefined {\n let answer: Op[] | null | undefined;\n let threw = false;\n runEvery(behaviors, (b) => {\n try {\n const r = b.onEnd?.(ctx, { ...own, answered: threw || answer !== undefined } as TEnd);\n if (answer === undefined && r !== undefined) answer = r;\n } catch (err) {\n threw = true;\n throw err;\n }\n });\n return answer;\n}\n\n/** Runs `step` for every item, a throwing one included, then rethrows the\n * first error. For steps that each release something of their own. */\nfunction runEvery<T>(items: readonly T[], step: (item: T) => void): void {\n const errors: unknown[] = [];\n for (const item of items) {\n try {\n step(item);\n } catch (err) {\n errors.push(err);\n }\n }\n if (errors.length > 0) throw errors[0];\n}\n\n/** Runs every behavior's `onCancel`, for a gesture closing without a commit.\n * One that throws does not stop the rest; its error is rethrown after. */\nexport function runBehaviorCancel<TCtx>(\n behaviors: readonly { onCancel?(ctx: TCtx): void }[],\n ctx: TCtx,\n): void {\n runEvery(behaviors, (b) => b.onCancel?.(ctx));\n}\n\n/** Runs every behavior's `onSettled`, once the gesture's commit has landed or\n * its cancel has run. One that throws does not stop the rest; its error is\n * rethrown after. */\nexport function runBehaviorSettled<TCtx>(\n behaviors: readonly { onSettled?(ctx: TCtx, committed: boolean): void }[],\n ctx: TCtx,\n committed: boolean,\n): void {\n runEvery(behaviors, (b) => b.onSettled?.(ctx, committed));\n}\n\n/** What {@link closeGesture} closes. */\nexport interface ClosingGesture<TCtx> {\n hold: PoseHold<unknown>;\n /** The action's own buffer of this frame's poses, emptied at the close. */\n previews: Map<NodeId, unknown>;\n behaviors: readonly { onSettled?(ctx: TCtx, committed: boolean): void }[];\n ctx: TCtx;\n lifecycle: GestureLifecycle;\n}\n\n/**\n * The close a transform action runs from its `finally`, commit or cancel:\n * drop the preview overrides, tell the behaviors, then fire `onGestureEnd`,\n * which fires even when a behavior's `onSettled` throws; the first error is\n * rethrown.\n */\nexport function closeGesture<TCtx>(gesture: ClosingGesture<TCtx>, committed: boolean): void {\n gesture.hold.drop();\n gesture.previews.clear();\n runEvery([\n () => runBehaviorSettled(gesture.behaviors, gesture.ctx, committed),\n () => gesture.lifecycle.end(committed),\n ], (step) => step());\n}\n"],"mappings":";;;;;AAmCA,SAAgB,uBAAuB,GAAqD;CAC1F,MAAM,MAA+B,CAAC;CACtC,IAAI,EAAE,UAAU,QAAW,IAAI,QAAQ,EAAE;CACzC,IAAI,EAAE,cAAc,QAAW,IAAI,YAAY,EAAE;CACjD,IAAI,EAAE,gBAAgB,IAAI,iBAAiB,EAAE;CAC7C,IAAI,EAAE,cAAc,IAAI,eAAe,EAAE;CACzC,OAAO;AACT;AAcA,SAAgB,qBACd,QACA,cACA,YAAuD,CAAC,GACtC;CAClB,MAAM,IAAK,UAAU,CAAC;CACtB,IAAI,UAAU;CACd,IAAI,QAAQ;CACZ,OAAO;EACL,OAAO,EAAE,SAAS;EAClB,WAAW,QAAQ,EAAE,SAAS,IAAI,EAAE,EAAE,SAAS;EAC/C,WAAW,EAAE,aAAa,UAAU,MAAM,MAAM,EAAE,qBAAqB,IAAI;EAC3E,MAAM,KAAK;GACT,IAAI,SAAS;GACb,UAAU;GACV,EAAE,iBAAiB,CAAC,GAAG,GAAG,CAAC;EAC7B;EACA,IAAI,WAAW;GACb,IAAI,CAAC,WAAW,OAAO;GACvB,QAAQ;GACR,EAAE,eAAe,SAAS;EAC5B;CACF;AACF;;;;;;;AAQA,SAAgB,iBACd,QAMA,WACA,OACS;CACT,MAAM,MAAM,OAAO,SAAS,OAAO,OAAO,OAAO,UAAU,SAAS,KAAK,CAAC,IAAI;CAC9E,IAAI,CAAC,KAAK,OAAO;CACjB,IAAI,UAAU,WAAW;EACvB,IAAI;GACF,OAAO,MAAM,gBAAgB;IAC3B,KAAK,MAAM,MAAM,KAAK,GAAG,MAAM,OAAO,OAAO;GAC/C,CAAC;EACH,SAAS,KAAK;GAEZ,IAAI,EAAE,eAAe,sBAAsB,MAAM;GACjD,OAAO;EACT;EACA,OAAO;CACT;CACA,MAAM,QAAQ,UAAU,SAAS,GAAG;CACpC,IAAI,CAAC,OAAO,UAAU,OAAO,OAAO,MAAM,WAAW,KAAK,OAAO,OAAO,OAAO;CAC/E,OAAO,SAAS,KAAK,KAAK;CAC1B,OAAO;AACT;;;;;;;;AAeA,SAAgB,kBACd,WACA,KACA,GAAG,CAAC,MACqB;CACzB,IAAI;CACJ,IAAI,QAAQ;CACZ,SAAS,YAAY,MAAM;EACzB,IAAI;GACF,MAAM,IAAI,EAAE,QAAQ,KAAK;IAAE,GAAG;IAAK,UAAU,SAAS,WAAW;GAAU,CAAS;GACpF,IAAI,WAAW,UAAa,MAAM,QAAW,SAAS;EACxD,SAAS,KAAK;GACZ,QAAQ;GACR,MAAM;EACR;CACF,CAAC;CACD,OAAO;AACT;;;AAIA,SAAS,SAAY,OAAqB,MAA+B;CACvE,MAAM,SAAoB,CAAC;CAC3B,KAAK,MAAM,QAAQ,OACjB,IAAI;EACF,KAAK,IAAI;CACX,SAAS,KAAK;EACZ,OAAO,KAAK,GAAG;CACjB;CAEF,IAAI,OAAO,SAAS,GAAG,MAAM,OAAO;AACtC;;;AAIA,SAAgB,kBACd,WACA,KACM;CACN,SAAS,YAAY,MAAM,EAAE,WAAW,GAAG,CAAC;AAC9C;;;;AAKA,SAAgB,mBACd,WACA,KACA,WACM;CACN,SAAS,YAAY,MAAM,EAAE,YAAY,KAAK,SAAS,CAAC;AAC1D;;;;;;;AAkBA,SAAgB,aAAmB,SAA+B,WAA0B;CAC1F,QAAQ,KAAK,KAAK;CAClB,QAAQ,SAAS,MAAM;CACvB,SAAS,OACD,mBAAmB,QAAQ,WAAW,QAAQ,KAAK,SAAS,SAC5D,QAAQ,UAAU,IAAI,SAAS,CACvC,IAAI,SAAS,KAAK,CAAC;AACrB"}
@@ -59,8 +59,7 @@ var insertAction = inPlane({
59
59
  const live = ctx.deps.insertLive;
60
60
  if (live) live.gesture = gesture;
61
61
  const scene = ctx.deps.scene;
62
- const into = ctx.deps.insertInto?.get() ?? null;
63
- const copies = scene ? copiesWithin(scene, into, scenePaintedPoseOf(scene)) : [];
62
+ const copies = scene ? copiesWithin(scene, session.parent, scenePaintedPoseOf(scene)) : [];
64
63
  return {
65
64
  kind: "insert",
66
65
  onMove(moveCtx) {
@@ -1 +1 @@
1
- {"version":3,"file":"action.js","names":[],"sources":["../../../../src/interactions/actions/insert/action.ts"],"sourcesContent":["import type { Action, NodeId } from '@weasel-js/routing';\nimport type { InvocationCtx, OngoingHandle, BindingOpts, OngoingOverlay } from '@weasel-js/routing';\nimport { resolveParams } from '@weasel-js/routing';\nimport { shapeKindInfo } from 'core/shapeKinds';\nimport type { KitInsertShape } from 'core/shapeKinds';\nimport { SNAP_ROLES } from 'features/snap/roles';\nimport { runBehaviorSettled } from '../gestureLifecycle';\nimport { inPlane, insertLayer } from '../planeInput';\nimport { copiesWithin } from 'canvas/copiesAbove';\nimport { scenePaintedPoseOf } from 'canvas/derivedPath';\nimport { cancelInsert, commitInsert } from './commit';\nimport { carryStart, nextFrame } from './frame';\nimport type { InsertLiveGesture } from './live';\nimport { beginInsert } from './session';\nimport { insertKind, insertShape } from './shape';\n\n/**\n * Drag-to-insert. The node `kind` is read from `opts.params.kind`.\n *\n * The drag's start and current point snap through the `snap` dep's `point`\n * sessions (never freehand pencil samples). While `snap.constrain` (Shift) is\n * held, a line's end stays on the 15° line through the snapped start nearest\n * the pointer, and lands where that line meets a target. Behaviors from the\n * binding's `opts.behaviors` (`InsertBehavior[]`) run over the two points\n * after that; on release the first answer wins (`null` aborts, `Op[]` commits\n * in place of the insert).\n *\n * The new node has no scene id until commit, so the live preview is the\n * `overlay()` surface with `kind: 'insertPreview'`. A consumer-defined kind\n * the kit cannot draw skips the preview and still commits on release.\n */\nexport const insertAction: Action & { requires: string[] } = inPlane({\n id: 'insert',\n label: 'Insert',\n group: 'insert',\n eligible: { capability: 'creates-shapes' },\n modifierRoles: SNAP_ROLES,\n requires: ['insert', 'insertLive', 'insertInto', 'selection', 'snap', 'textEdit', 'scene', 'applyOps', 'view', 'kitSettings'],\n invoker: {\n timing: 'ongoing',\n start(ctx: InvocationCtx, opts?: BindingOpts): OngoingHandle {\n const begun = beginInsert(ctx, opts);\n if (!begun) return {};\n const { session, readers } = begun;\n let frame = begun.frame;\n const gesture: InsertLiveGesture = { open: true, userRotation: 0, repositioning: false };\n const live = ctx.deps.insertLive;\n if (live) live.gesture = gesture;\n // Where the shape will land decides the copies it will be drawn in.\n const scene = ctx.deps.scene;\n const into = (ctx.deps.insertInto?.get() ?? null) as NodeId | null;\n const copies = scene ? copiesWithin(scene, into, scenePaintedPoseOf(scene)) : [];\n\n return {\n kind: 'insert',\n onMove(moveCtx: InvocationCtx): void {\n if (gesture.repositioning) carryStart(session, frame.pointer, moveCtx.world, moveCtx);\n frame = nextFrame(session, readers, frame, moveCtx);\n },\n overlay(): OngoingOverlay | null {\n if (!gesture.open) return null;\n // Resolve params on every overlay() so thunked params (polygon\n // sides ticking via ArrowUp mid-drag) reflect in the live preview.\n const resolved = resolveParams(session.opts?.params);\n if (!shapeKindInfo(insertKind(resolved))?.insertPreview) return null;\n const { bounds, extras, start } = insertShape(resolved, frame, frame.points, gesture.userRotation);\n return {\n kind: 'insertPreview',\n shape: extras.kind as KitInsertShape,\n bounds,\n extras,\n // Anchor dot at the click point: radial shapes have no vertex\n // there, and in center mode it marks the growth axis.\n anchorPoint: { x: start.x, y: start.y },\n ...(copies.length > 0 ? { copies } : {}),\n };\n },\n onEnd(endCtx: InvocationCtx, reason: 'commit' | 'cancel'): void {\n gesture.open = false;\n if (live?.gesture === gesture) live.gesture = null;\n let committed = false;\n try {\n if (reason === 'cancel') cancelInsert(session);\n else committed = commitInsert(session, frame, endCtx.drag?.points ?? frame.points, gesture.userRotation);\n } finally {\n session.snap.close();\n runBehaviorSettled(session.behaviors, session.gestureCtx, committed);\n }\n },\n };\n },\n },\n /** Insert needs no selection; anything but `true` blocks dispatcher-routed inserts. */\n enabled: () => true as const,\n}, insertLayer);\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BA,IAAa,eAAgD,QAAQ;CACnE,IAAI;CACJ,OAAO;CACP,OAAO;CACP,UAAU,EAAE,YAAY,iBAAiB;CACzC,eAAe;CACf,UAAU;EAAC;EAAU;EAAc;EAAc;EAAa;EAAQ;EAAY;EAAS;EAAY;EAAQ;CAAa;CAC5H,SAAS;EACP,QAAQ;EACR,MAAM,KAAoB,MAAmC;GAC3D,MAAM,QAAQ,YAAY,KAAK,IAAI;GACnC,IAAI,CAAC,OAAO,OAAO,CAAC;GACpB,MAAM,EAAE,SAAS,YAAY;GAC7B,IAAI,QAAQ,MAAM;GAClB,MAAM,UAA6B;IAAE,MAAM;IAAM,cAAc;IAAG,eAAe;GAAM;GACvF,MAAM,OAAO,IAAI,KAAK;GACtB,IAAI,MAAM,KAAK,UAAU;GAEzB,MAAM,QAAQ,IAAI,KAAK;GACvB,MAAM,OAAQ,IAAI,KAAK,YAAY,IAAI,KAAK;GAC5C,MAAM,SAAS,QAAQ,aAAa,OAAO,MAAM,mBAAmB,KAAK,CAAC,IAAI,CAAC;GAE/E,OAAO;IACL,MAAM;IACN,OAAO,SAA8B;KACnC,IAAI,QAAQ,eAAe,WAAW,SAAS,MAAM,SAAS,QAAQ,OAAO,OAAO;KACpF,QAAQ,UAAU,SAAS,SAAS,OAAO,OAAO;IACpD;IACA,UAAiC;KAC/B,IAAI,CAAC,QAAQ,MAAM,OAAO;KAG1B,MAAM,WAAW,cAAc,QAAQ,MAAM,MAAM;KACnD,IAAI,CAAC,cAAc,WAAW,QAAQ,CAAC,CAAC,EAAE,eAAe,OAAO;KAChE,MAAM,EAAE,QAAQ,QAAQ,UAAU,YAAY,UAAU,OAAO,MAAM,QAAQ,QAAQ,YAAY;KACjG,OAAO;MACL,MAAM;MACN,OAAO,OAAO;MACd;MACA;MAGA,aAAa;OAAE,GAAG,MAAM;OAAG,GAAG,MAAM;MAAE;MACtC,GAAI,OAAO,SAAS,IAAI,EAAE,OAAO,IAAI,CAAC;KACxC;IACF;IACA,MAAM,QAAuB,QAAmC;KAC9D,QAAQ,OAAO;KACf,IAAI,MAAM,YAAY,SAAS,KAAK,UAAU;KAC9C,IAAI,YAAY;KAChB,IAAI;MACF,IAAI,WAAW,UAAU,aAAa,OAAO;WACxC,YAAY,aAAa,SAAS,OAAO,OAAO,MAAM,UAAU,MAAM,QAAQ,QAAQ,YAAY;KACzG,UAAU;MACR,QAAQ,KAAK,MAAM;MACnB,mBAAmB,QAAQ,WAAW,QAAQ,YAAY,SAAS;KACrE;IACF;GACF;EACF;CACF;;CAEA,eAAe;AACjB,GAAG,WAAW"}
1
+ {"version":3,"file":"action.js","names":[],"sources":["../../../../src/interactions/actions/insert/action.ts"],"sourcesContent":["import type { Action } from '@weasel-js/routing';\nimport type { InvocationCtx, OngoingHandle, BindingOpts, OngoingOverlay } from '@weasel-js/routing';\nimport { resolveParams } from '@weasel-js/routing';\nimport { shapeKindInfo } from 'core/shapeKinds';\nimport type { KitInsertShape } from 'core/shapeKinds';\nimport { SNAP_ROLES } from 'features/snap/roles';\nimport { runBehaviorSettled } from '../gestureLifecycle';\nimport { inPlane, insertLayer } from '../planeInput';\nimport { copiesWithin } from 'canvas/copiesAbove';\nimport { scenePaintedPoseOf } from 'canvas/derivedPath';\nimport { cancelInsert, commitInsert } from './commit';\nimport { carryStart, nextFrame } from './frame';\nimport type { InsertLiveGesture } from './live';\nimport { beginInsert } from './session';\nimport { insertKind, insertShape } from './shape';\n\n/**\n * Drag-to-insert. The node `kind` is read from `opts.params.kind`.\n *\n * The drag's start and current point snap through the `snap` dep's `point`\n * sessions (never freehand pencil samples). While `snap.constrain` (Shift) is\n * held, a line's end stays on the 15° line through the snapped start nearest\n * the pointer, and lands where that line meets a target. Behaviors from the\n * binding's `opts.behaviors` (`InsertBehavior[]`) run over the two points\n * after that; on release the first answer wins (`null` aborts, `Op[]` commits\n * in place of the insert).\n *\n * The new node has no scene id until commit, so the live preview is the\n * `overlay()` surface with `kind: 'insertPreview'`. A consumer-defined kind\n * the kit cannot draw skips the preview and still commits on release.\n */\nexport const insertAction: Action & { requires: string[] } = inPlane({\n id: 'insert',\n label: 'Insert',\n group: 'insert',\n eligible: { capability: 'creates-shapes' },\n modifierRoles: SNAP_ROLES,\n requires: ['insert', 'insertLive', 'insertInto', 'selection', 'snap', 'textEdit', 'scene', 'applyOps', 'view', 'kitSettings'],\n invoker: {\n timing: 'ongoing',\n start(ctx: InvocationCtx, opts?: BindingOpts): OngoingHandle {\n const begun = beginInsert(ctx, opts);\n if (!begun) return {};\n const { session, readers } = begun;\n let frame = begun.frame;\n const gesture: InsertLiveGesture = { open: true, userRotation: 0, repositioning: false };\n const live = ctx.deps.insertLive;\n if (live) live.gesture = gesture;\n // Where the shape will land decides the copies it will be drawn in.\n const scene = ctx.deps.scene;\n const copies = scene ? copiesWithin(scene, session.parent, scenePaintedPoseOf(scene)) : [];\n\n return {\n kind: 'insert',\n onMove(moveCtx: InvocationCtx): void {\n if (gesture.repositioning) carryStart(session, frame.pointer, moveCtx.world, moveCtx);\n frame = nextFrame(session, readers, frame, moveCtx);\n },\n overlay(): OngoingOverlay | null {\n if (!gesture.open) return null;\n // Resolve params on every overlay() so thunked params (polygon\n // sides ticking via ArrowUp mid-drag) reflect in the live preview.\n const resolved = resolveParams(session.opts?.params);\n if (!shapeKindInfo(insertKind(resolved))?.insertPreview) return null;\n const { bounds, extras, start } = insertShape(resolved, frame, frame.points, gesture.userRotation);\n return {\n kind: 'insertPreview',\n shape: extras.kind as KitInsertShape,\n bounds,\n extras,\n // Anchor dot at the click point: radial shapes have no vertex\n // there, and in center mode it marks the growth axis.\n anchorPoint: { x: start.x, y: start.y },\n ...(copies.length > 0 ? { copies } : {}),\n };\n },\n onEnd(endCtx: InvocationCtx, reason: 'commit' | 'cancel'): void {\n gesture.open = false;\n if (live?.gesture === gesture) live.gesture = null;\n let committed = false;\n try {\n if (reason === 'cancel') cancelInsert(session);\n else committed = commitInsert(session, frame, endCtx.drag?.points ?? frame.points, gesture.userRotation);\n } finally {\n session.snap.close();\n runBehaviorSettled(session.behaviors, session.gestureCtx, committed);\n }\n },\n };\n },\n },\n /** Insert needs no selection; anything but `true` blocks dispatcher-routed inserts. */\n enabled: () => true as const,\n}, insertLayer);\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BA,IAAa,eAAgD,QAAQ;CACnE,IAAI;CACJ,OAAO;CACP,OAAO;CACP,UAAU,EAAE,YAAY,iBAAiB;CACzC,eAAe;CACf,UAAU;EAAC;EAAU;EAAc;EAAc;EAAa;EAAQ;EAAY;EAAS;EAAY;EAAQ;CAAa;CAC5H,SAAS;EACP,QAAQ;EACR,MAAM,KAAoB,MAAmC;GAC3D,MAAM,QAAQ,YAAY,KAAK,IAAI;GACnC,IAAI,CAAC,OAAO,OAAO,CAAC;GACpB,MAAM,EAAE,SAAS,YAAY;GAC7B,IAAI,QAAQ,MAAM;GAClB,MAAM,UAA6B;IAAE,MAAM;IAAM,cAAc;IAAG,eAAe;GAAM;GACvF,MAAM,OAAO,IAAI,KAAK;GACtB,IAAI,MAAM,KAAK,UAAU;GAEzB,MAAM,QAAQ,IAAI,KAAK;GACvB,MAAM,SAAS,QAAQ,aAAa,OAAO,QAAQ,QAAQ,mBAAmB,KAAK,CAAC,IAAI,CAAC;GAEzF,OAAO;IACL,MAAM;IACN,OAAO,SAA8B;KACnC,IAAI,QAAQ,eAAe,WAAW,SAAS,MAAM,SAAS,QAAQ,OAAO,OAAO;KACpF,QAAQ,UAAU,SAAS,SAAS,OAAO,OAAO;IACpD;IACA,UAAiC;KAC/B,IAAI,CAAC,QAAQ,MAAM,OAAO;KAG1B,MAAM,WAAW,cAAc,QAAQ,MAAM,MAAM;KACnD,IAAI,CAAC,cAAc,WAAW,QAAQ,CAAC,CAAC,EAAE,eAAe,OAAO;KAChE,MAAM,EAAE,QAAQ,QAAQ,UAAU,YAAY,UAAU,OAAO,MAAM,QAAQ,QAAQ,YAAY;KACjG,OAAO;MACL,MAAM;MACN,OAAO,OAAO;MACd;MACA;MAGA,aAAa;OAAE,GAAG,MAAM;OAAG,GAAG,MAAM;MAAE;MACtC,GAAI,OAAO,SAAS,IAAI,EAAE,OAAO,IAAI,CAAC;KACxC;IACF;IACA,MAAM,QAAuB,QAAmC;KAC9D,QAAQ,OAAO;KACf,IAAI,MAAM,YAAY,SAAS,KAAK,UAAU;KAC9C,IAAI,YAAY;KAChB,IAAI;MACF,IAAI,WAAW,UAAU,aAAa,OAAO;WACxC,YAAY,aAAa,SAAS,OAAO,OAAO,MAAM,UAAU,MAAM,QAAQ,QAAQ,YAAY;KACzG,UAAU;MACR,QAAQ,KAAK,MAAM;MACnB,mBAAmB,QAAQ,WAAW,QAAQ,YAAY,SAAS;KACrE;IACF;GACF;EACF;CACF;;CAEA,eAAe;AACjB,GAAG,WAAW"}
@@ -1,5 +1,5 @@
1
- import { commitGestureOps, readGestureLifecycle, reduceBehaviorEnd, runBehaviorCancel } from "../gestureLifecycle.js";
2
1
  import { defaultCommitAdapter } from "../defaultCommitAdapter.js";
2
+ import { commitGestureOps, readGestureLifecycle, reduceBehaviorEnd, runBehaviorCancel } from "../gestureLifecycle.js";
3
3
  import { shapeKindInfo } from "../../../core/shapeKinds.js";
4
4
  import { insertShape, isCommittableExtent } from "./shape.js";
5
5
  import { resolveParams } from "@weasel-js/routing";
@@ -0,0 +1,11 @@
1
+ //#region src/interactions/actions/insert/parent.ts
2
+ /** The container an insert lands in: the one the `insertInto` dep's `into`
3
+ * names, or null, the top of the tree, when it names no container. */
4
+ function insertParent(scene, into) {
5
+ if (into == null || !scene) return null;
6
+ return scene.get(into)?.kind === "container" ? into : null;
7
+ }
8
+
9
+ //#endregion
10
+ export { insertParent };
11
+ //# sourceMappingURL=parent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parent.js","names":[],"sources":["../../../../src/interactions/actions/insert/parent.ts"],"sourcesContent":["import type { NodeId } from 'core/scene/types';\n\n/** What finding an insert's container reads of a scene. A `Scene` satisfies it. */\ninterface ContainerReader {\n get(id: NodeId): { kind: string } | undefined;\n}\n\n/** The container an insert lands in: the one the `insertInto` dep's `into`\n * names, or null, the top of the tree, when it names no container. */\nexport function insertParent(scene: ContainerReader | undefined, into: string | null | undefined): NodeId | null {\n if (into == null || !scene) return null;\n return scene.get(into as NodeId)?.kind === 'container' ? (into as NodeId) : null;\n}\n"],"mappings":";;;AASA,SAAgB,aAAa,OAAoC,MAAgD;CAC/G,IAAI,QAAQ,QAAQ,CAAC,OAAO,OAAO;CACnC,OAAO,MAAM,IAAI,IAAc,CAAC,EAAE,SAAS,cAAe,OAAkB;AAC9E"}
@@ -3,6 +3,7 @@ import { SNAP_ROLES, snapMods } from "../../../features/snap/roles.js";
3
3
  import { minSizeOf } from "../../../core/scene/minSize.js";
4
4
  import { insertKind } from "./shape.js";
5
5
  import { enterInsertedText } from "./commit.js";
6
+ import { insertParent } from "./parent.js";
6
7
 
7
8
  //#region src/interactions/actions/insert/placeAction.ts
8
9
  /** What the dispatcher lays under an immediate action's params for a click. */
@@ -41,9 +42,11 @@ var placeAction = inPlane({
41
42
  modifierRoles: SNAP_ROLES,
42
43
  requires: [
43
44
  "insert",
45
+ "insertInto",
44
46
  "selection",
45
47
  "snap",
46
- "textEdit"
48
+ "textEdit",
49
+ "scene"
47
50
  ],
48
51
  invoker: {
49
52
  timing: "immediate",
@@ -60,12 +63,14 @@ var placeAction = inPlane({
60
63
  if (!dep || !size || typeof x !== "number" || typeof y !== "number") return;
61
64
  if (!(size.width > 0 && size.height > 0)) return;
62
65
  deps.selection?.clear();
66
+ const parent = insertParent(deps.scene, deps.insertInto?.get());
63
67
  const snap = deps.snap?.begin({
64
68
  gesture: "point",
65
69
  press: {
66
70
  x,
67
71
  y
68
- }
72
+ },
73
+ ...parent === null ? {} : { parent }
69
74
  });
70
75
  const mods = snapMods({ modifiers: params?.["mods"] ?? NO_KEYS });
71
76
  const at = snap ? snap.at({
@@ -1 +1 @@
1
- {"version":3,"file":"placeAction.js","names":[],"sources":["../../../../src/interactions/actions/insert/placeAction.ts"],"sourcesContent":["import type { Action, ActionDeps, ModifierState } from '@weasel-js/routing';\nimport { SNAP_ROLES, snapMods } from 'features/snap/roles';\nimport type { InsertExtras } from '../depSchema';\nimport { inPlane, insertLayer } from '../planeInput';\nimport { enterInsertedText } from './commit';\nimport { insertKind } from './shape';\nimport { minSizeOf } from 'core/scene/minSize';\n\n/** What the dispatcher lays under an immediate action's params for a click. */\nconst CLICK_FIELDS = ['worldX', 'worldY', 'pressX', 'pressY', 'affordance', 'mods'] as const;\n\nconst NO_KEYS: ModifierState = { alt: false, ctrl: false, meta: false, shift: false };\n\n/**\n * Click-to-insert: the companion to `insertAction` for a click, which draws\n * no box. It commits a node of `params.kind` at `params.size`, centered on the\n * click, snapped through a `point` session of the `snap` dep unless the\n * click held `snap.suspend` (Ctrl), and commits\n * through the same `insert` dep a drag commits through. The rest of the\n * binding's params are the insert's extras, as a drag's are.\n *\n * A `minSize` in the params floors the size, and goes on to the node.\n *\n * A binding with no `size` places nothing: the kind's extent is the tool's to\n * name, and a click has none of its own.\n */\nexport const placeAction: Action & { requires: string[] } = inPlane({\n id: 'place',\n label: 'Place',\n group: 'insert',\n eligible: { capability: 'creates-shapes' },\n modifierRoles: SNAP_ROLES,\n requires: ['insert', 'selection', 'snap', 'textEdit'],\n invoker: {\n timing: 'immediate',\n run(deps: ActionDeps, params?: Record<string, unknown>): void {\n const dep = deps.insert;\n const asked = params?.['size'] as { width: number; height: number } | undefined;\n const min = minSizeOf(params);\n const size = asked && min\n ? { width: Math.max(asked.width, min.width), height: Math.max(asked.height, min.height) }\n : asked;\n const x = params?.['worldX'];\n const y = params?.['worldY'];\n if (!dep || !size || typeof x !== 'number' || typeof y !== 'number') return;\n if (!(size.width > 0 && size.height > 0)) return;\n\n deps.selection?.clear();\n const snap = deps.snap?.begin({ gesture: 'point', press: { x, y } });\n const mods = snapMods({ modifiers: (params?.['mods'] as ModifierState | undefined) ?? NO_KEYS });\n const at = snap ? snap.at({ x, y }, mods).point : { x, y };\n snap?.end();\n const extras: Record<string, unknown> = { ...params, kind: insertKind(params) };\n for (const k of [...CLICK_FIELDS, 'size']) delete extras[k];\n const bounds = { x: at.x - size.width / 2, y: at.y - size.height / 2, width: size.width, height: size.height };\n const ends = { start: at, end: { x: at.x + size.width / 2, y: at.y + size.height / 2 }, fromCenter: true };\n const id = dep.commit(bounds, extras as InsertExtras, ends);\n enterInsertedText(deps.textEdit, id === null ? null : String(id), extras.kind as string);\n },\n },\n /** Like `insert`, needs no selection. */\n enabled: () => true as const,\n}, insertLayer);\n"],"mappings":";;;;;;;;AASA,IAAM,eAAe;CAAC;CAAU;CAAU;CAAU;CAAU;CAAc;AAAM;AAElF,IAAM,UAAyB;CAAE,KAAK;CAAO,MAAM;CAAO,MAAM;CAAO,OAAO;AAAM;;;;;;;;;;;;;;AAepF,IAAa,cAA+C,QAAQ;CAClE,IAAI;CACJ,OAAO;CACP,OAAO;CACP,UAAU,EAAE,YAAY,iBAAiB;CACzC,eAAe;CACf,UAAU;EAAC;EAAU;EAAa;EAAQ;CAAU;CACpD,SAAS;EACP,QAAQ;EACR,IAAI,MAAkB,QAAwC;GAC5D,MAAM,MAAM,KAAK;GACjB,MAAM,QAAQ,SAAS;GACvB,MAAM,MAAM,UAAU,MAAM;GAC5B,MAAM,OAAO,SAAS,MAClB;IAAE,OAAO,KAAK,IAAI,MAAM,OAAO,IAAI,KAAK;IAAG,QAAQ,KAAK,IAAI,MAAM,QAAQ,IAAI,MAAM;GAAE,IACtF;GACJ,MAAM,IAAI,SAAS;GACnB,MAAM,IAAI,SAAS;GACnB,IAAI,CAAC,OAAO,CAAC,QAAQ,OAAO,MAAM,YAAY,OAAO,MAAM,UAAU;GACrE,IAAI,EAAE,KAAK,QAAQ,KAAK,KAAK,SAAS,IAAI;GAE1C,KAAK,WAAW,MAAM;GACtB,MAAM,OAAO,KAAK,MAAM,MAAM;IAAE,SAAS;IAAS,OAAO;KAAE;KAAG;IAAE;GAAE,CAAC;GACnE,MAAM,OAAO,SAAS,EAAE,WAAY,SAAS,WAAyC,QAAQ,CAAC;GAC/F,MAAM,KAAK,OAAO,KAAK,GAAG;IAAE;IAAG;GAAE,GAAG,IAAI,CAAC,CAAC,QAAQ;IAAE;IAAG;GAAE;GACzD,MAAM,IAAI;GACV,MAAM,SAAkC;IAAE,GAAG;IAAQ,MAAM,WAAW,MAAM;GAAE;GAC9E,KAAK,MAAM,KAAK,CAAC,GAAG,cAAc,MAAM,GAAG,OAAO,OAAO;GACzD,MAAM,SAAS;IAAE,GAAG,GAAG,IAAI,KAAK,QAAQ;IAAG,GAAG,GAAG,IAAI,KAAK,SAAS;IAAG,OAAO,KAAK;IAAO,QAAQ,KAAK;GAAO;GAC7G,MAAM,OAAO;IAAE,OAAO;IAAI,KAAK;KAAE,GAAG,GAAG,IAAI,KAAK,QAAQ;KAAG,GAAG,GAAG,IAAI,KAAK,SAAS;IAAE;IAAG,YAAY;GAAK;GACzG,MAAM,KAAK,IAAI,OAAO,QAAQ,QAAwB,IAAI;GAC1D,kBAAkB,KAAK,UAAU,OAAO,OAAO,OAAO,OAAO,EAAE,GAAG,OAAO,IAAc;EACzF;CACF;;CAEA,eAAe;AACjB,GAAG,WAAW"}
1
+ {"version":3,"file":"placeAction.js","names":[],"sources":["../../../../src/interactions/actions/insert/placeAction.ts"],"sourcesContent":["import type { Action, ActionDeps, ModifierState } from '@weasel-js/routing';\nimport { SNAP_ROLES, snapMods } from 'features/snap/roles';\nimport type { InsertExtras } from '../depSchema';\nimport { inPlane, insertLayer } from '../planeInput';\nimport { enterInsertedText } from './commit';\nimport { insertParent } from './parent';\nimport { insertKind } from './shape';\nimport { minSizeOf } from 'core/scene/minSize';\n\n/** What the dispatcher lays under an immediate action's params for a click. */\nconst CLICK_FIELDS = ['worldX', 'worldY', 'pressX', 'pressY', 'affordance', 'mods'] as const;\n\nconst NO_KEYS: ModifierState = { alt: false, ctrl: false, meta: false, shift: false };\n\n/**\n * Click-to-insert: the companion to `insertAction` for a click, which draws\n * no box. It commits a node of `params.kind` at `params.size`, centered on the\n * click, snapped through a `point` session of the `snap` dep unless the\n * click held `snap.suspend` (Ctrl), and commits\n * through the same `insert` dep a drag commits through. The rest of the\n * binding's params are the insert's extras, as a drag's are.\n *\n * A `minSize` in the params floors the size, and goes on to the node.\n *\n * A binding with no `size` places nothing: the kind's extent is the tool's to\n * name, and a click has none of its own.\n */\nexport const placeAction: Action & { requires: string[] } = inPlane({\n id: 'place',\n label: 'Place',\n group: 'insert',\n eligible: { capability: 'creates-shapes' },\n modifierRoles: SNAP_ROLES,\n requires: ['insert', 'insertInto', 'selection', 'snap', 'textEdit', 'scene'],\n invoker: {\n timing: 'immediate',\n run(deps: ActionDeps, params?: Record<string, unknown>): void {\n const dep = deps.insert;\n const asked = params?.['size'] as { width: number; height: number } | undefined;\n const min = minSizeOf(params);\n const size = asked && min\n ? { width: Math.max(asked.width, min.width), height: Math.max(asked.height, min.height) }\n : asked;\n const x = params?.['worldX'];\n const y = params?.['worldY'];\n if (!dep || !size || typeof x !== 'number' || typeof y !== 'number') return;\n if (!(size.width > 0 && size.height > 0)) return;\n\n deps.selection?.clear();\n const parent = insertParent(deps.scene, deps.insertInto?.get());\n const snap = deps.snap?.begin({ gesture: 'point', press: { x, y }, ...(parent === null ? {} : { parent }) });\n const mods = snapMods({ modifiers: (params?.['mods'] as ModifierState | undefined) ?? NO_KEYS });\n const at = snap ? snap.at({ x, y }, mods).point : { x, y };\n snap?.end();\n const extras: Record<string, unknown> = { ...params, kind: insertKind(params) };\n for (const k of [...CLICK_FIELDS, 'size']) delete extras[k];\n const bounds = { x: at.x - size.width / 2, y: at.y - size.height / 2, width: size.width, height: size.height };\n const ends = { start: at, end: { x: at.x + size.width / 2, y: at.y + size.height / 2 }, fromCenter: true };\n const id = dep.commit(bounds, extras as InsertExtras, ends);\n enterInsertedText(deps.textEdit, id === null ? null : String(id), extras.kind as string);\n },\n },\n /** Like `insert`, needs no selection. */\n enabled: () => true as const,\n}, insertLayer);\n"],"mappings":";;;;;;;;;AAUA,IAAM,eAAe;CAAC;CAAU;CAAU;CAAU;CAAU;CAAc;AAAM;AAElF,IAAM,UAAyB;CAAE,KAAK;CAAO,MAAM;CAAO,MAAM;CAAO,OAAO;AAAM;;;;;;;;;;;;;;AAepF,IAAa,cAA+C,QAAQ;CAClE,IAAI;CACJ,OAAO;CACP,OAAO;CACP,UAAU,EAAE,YAAY,iBAAiB;CACzC,eAAe;CACf,UAAU;EAAC;EAAU;EAAc;EAAa;EAAQ;EAAY;CAAO;CAC3E,SAAS;EACP,QAAQ;EACR,IAAI,MAAkB,QAAwC;GAC5D,MAAM,MAAM,KAAK;GACjB,MAAM,QAAQ,SAAS;GACvB,MAAM,MAAM,UAAU,MAAM;GAC5B,MAAM,OAAO,SAAS,MAClB;IAAE,OAAO,KAAK,IAAI,MAAM,OAAO,IAAI,KAAK;IAAG,QAAQ,KAAK,IAAI,MAAM,QAAQ,IAAI,MAAM;GAAE,IACtF;GACJ,MAAM,IAAI,SAAS;GACnB,MAAM,IAAI,SAAS;GACnB,IAAI,CAAC,OAAO,CAAC,QAAQ,OAAO,MAAM,YAAY,OAAO,MAAM,UAAU;GACrE,IAAI,EAAE,KAAK,QAAQ,KAAK,KAAK,SAAS,IAAI;GAE1C,KAAK,WAAW,MAAM;GACtB,MAAM,SAAS,aAAa,KAAK,OAAO,KAAK,YAAY,IAAI,CAAC;GAC9D,MAAM,OAAO,KAAK,MAAM,MAAM;IAAE,SAAS;IAAS,OAAO;KAAE;KAAG;IAAE;IAAG,GAAI,WAAW,OAAO,CAAC,IAAI,EAAE,OAAO;GAAG,CAAC;GAC3G,MAAM,OAAO,SAAS,EAAE,WAAY,SAAS,WAAyC,QAAQ,CAAC;GAC/F,MAAM,KAAK,OAAO,KAAK,GAAG;IAAE;IAAG;GAAE,GAAG,IAAI,CAAC,CAAC,QAAQ;IAAE;IAAG;GAAE;GACzD,MAAM,IAAI;GACV,MAAM,SAAkC;IAAE,GAAG;IAAQ,MAAM,WAAW,MAAM;GAAE;GAC9E,KAAK,MAAM,KAAK,CAAC,GAAG,cAAc,MAAM,GAAG,OAAO,OAAO;GACzD,MAAM,SAAS;IAAE,GAAG,GAAG,IAAI,KAAK,QAAQ;IAAG,GAAG,GAAG,IAAI,KAAK,SAAS;IAAG,OAAO,KAAK;IAAO,QAAQ,KAAK;GAAO;GAC7G,MAAM,OAAO;IAAE,OAAO;IAAI,KAAK;KAAE,GAAG,GAAG,IAAI,KAAK,QAAQ;KAAG,GAAG,GAAG,IAAI,KAAK,SAAS;IAAE;IAAG,YAAY;GAAK;GACzG,MAAM,KAAK,IAAI,OAAO,QAAQ,QAAwB,IAAI;GAC1D,kBAAkB,KAAK,UAAU,OAAO,OAAO,OAAO,OAAO,EAAE,GAAG,OAAO,IAAc;EACzF;CACF;;CAEA,eAAe;AACjB,GAAG,WAAW"}
@@ -38,7 +38,8 @@ var INSERT_REPOSITION_BINDING = {
38
38
  ...heldKeySpec(" "),
39
39
  phase: "engaged"
40
40
  },
41
- actionId: "insert.reposition"
41
+ actionId: "insert.reposition",
42
+ opts: { id: "insert.reposition.held" }
42
43
  };
43
44
 
44
45
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"repositionAction.js","names":[],"sources":["../../../../src/interactions/actions/insert/repositionAction.ts"],"sourcesContent":["import { heldKeySpec, type Action, type GestureBinding } from '@weasel-js/routing';\nimport type { InsertLiveGesture } from './live';\n\n/**\n * Companion to `insertAction`: while its key is held, dragging moves the\n * shape being drawn instead of resizing it; letting go resumes resizing from\n * where the shape now sits. No-op when no insert is in flight.\n */\nexport const insertRepositionAction: Action = {\n id: 'insert.reposition',\n label: 'Insert — reposition',\n group: 'insert',\n eligible: { capability: 'creates-shapes' },\n invoker: {\n timing: 'ongoing',\n start: (ctx) => {\n const gesture = ctx.deps.insertLive?.gesture as InsertLiveGesture | null | undefined;\n if (!gesture || !gesture.open) return {};\n gesture.repositioning = true;\n return {\n kind: 'insert.reposition',\n onEnd: () => { gesture.repositioning = false; },\n };\n },\n },\n requires: ['insertLive'],\n};\n\n/**\n * The binding a shape-drawing tool adds so holding Space mid-draw repositions\n * the shape. Gated to the tool's own engaged phase, so Space between drags is\n * left to the offhand hand tool. Shift and Alt may be down with it, so a\n * constrained or from-center draw can be moved without letting go of them.\n */\nexport const INSERT_REPOSITION_BINDING: GestureBinding = {\n spec: { ...heldKeySpec(' '), phase: 'engaged' },\n actionId: 'insert.reposition',\n};\n"],"mappings":";;;;;;;;AAQA,IAAa,yBAAiC;CAC5C,IAAI;CACJ,OAAO;CACP,OAAO;CACP,UAAU,EAAE,YAAY,iBAAiB;CACzC,SAAS;EACP,QAAQ;EACR,QAAQ,QAAQ;GACd,MAAM,UAAU,IAAI,KAAK,YAAY;GACrC,IAAI,CAAC,WAAW,CAAC,QAAQ,MAAM,OAAO,CAAC;GACvC,QAAQ,gBAAgB;GACxB,OAAO;IACL,MAAM;IACN,aAAa;KAAE,QAAQ,gBAAgB;IAAO;GAChD;EACF;CACF;CACA,UAAU,CAAC,YAAY;AACzB;;;;;;;AAQA,IAAa,4BAA4C;CACvD,MAAM;EAAE,GAAG,YAAY,GAAG;EAAG,OAAO;CAAU;CAC9C,UAAU;AACZ"}
1
+ {"version":3,"file":"repositionAction.js","names":[],"sources":["../../../../src/interactions/actions/insert/repositionAction.ts"],"sourcesContent":["import { heldKeySpec, type Action, type GestureBinding } from '@weasel-js/routing';\nimport type { InsertLiveGesture } from './live';\n\n/**\n * Companion to `insertAction`: while its key is held, dragging moves the\n * shape being drawn instead of resizing it; letting go resumes resizing from\n * where the shape now sits. No-op when no insert is in flight.\n */\nexport const insertRepositionAction: Action = {\n id: 'insert.reposition',\n label: 'Insert — reposition',\n group: 'insert',\n eligible: { capability: 'creates-shapes' },\n invoker: {\n timing: 'ongoing',\n start: (ctx) => {\n const gesture = ctx.deps.insertLive?.gesture as InsertLiveGesture | null | undefined;\n if (!gesture || !gesture.open) return {};\n gesture.repositioning = true;\n return {\n kind: 'insert.reposition',\n onEnd: () => { gesture.repositioning = false; },\n };\n },\n },\n requires: ['insertLive'],\n};\n\n/**\n * The binding a shape-drawing tool adds so holding Space mid-draw repositions\n * the shape. Gated to the tool's own engaged phase, so Space between drags is\n * left to the offhand hand tool. Shift and Alt may be down with it, so a\n * constrained or from-center draw can be moved without letting go of them.\n */\nexport const INSERT_REPOSITION_BINDING: GestureBinding = {\n spec: { ...heldKeySpec(' '), phase: 'engaged' },\n actionId: 'insert.reposition',\n opts: { id: 'insert.reposition.held' },\n};\n"],"mappings":";;;;;;;;AAQA,IAAa,yBAAiC;CAC5C,IAAI;CACJ,OAAO;CACP,OAAO;CACP,UAAU,EAAE,YAAY,iBAAiB;CACzC,SAAS;EACP,QAAQ;EACR,QAAQ,QAAQ;GACd,MAAM,UAAU,IAAI,KAAK,YAAY;GACrC,IAAI,CAAC,WAAW,CAAC,QAAQ,MAAM,OAAO,CAAC;GACvC,QAAQ,gBAAgB;GACxB,OAAO;IACL,MAAM;IACN,aAAa;KAAE,QAAQ,gBAAgB;IAAO;GAChD;EACF;CACF;CACA,UAAU,CAAC,YAAY;AACzB;;;;;;;AAQA,IAAa,4BAA4C;CACvD,MAAM;EAAE,GAAG,YAAY,GAAG;EAAG,OAAO;CAAU;CAC9C,UAAU;CACV,MAAM,EAAE,IAAI,yBAAyB;AACvC"}
@@ -3,6 +3,7 @@ import { pointerStateOf } from "../pointerState.js";
3
3
  import { SNAP_ANGLE_STEP, snapMods } from "../../../features/snap/roles.js";
4
4
  import { insertKind } from "./shape.js";
5
5
  import { spanSnap } from "../../../features/snap/spanSnap.js";
6
+ import { insertParent } from "./parent.js";
6
7
  import { resolveParams } from "@weasel-js/routing";
7
8
 
8
9
  //#region src/interactions/actions/insert/session.ts
@@ -17,7 +18,9 @@ function beginInsert(ctx, opts) {
17
18
  const selection = ctx.deps.selection;
18
19
  const priorSelection = selection ? [...selection.get()] : [];
19
20
  if (selection && priorSelection.length > 0) selection.clear();
20
- const snap = spanSnap(ctx.deps.snap, () => insertKind(resolveParams(opts?.params)) === "line" ? { step: SNAP_ANGLE_STEP } : void 0);
21
+ const parent = insertParent(ctx.deps.scene, ctx.deps.insertInto?.get());
22
+ const constrain = () => insertKind(resolveParams(opts?.params)) === "line" ? { step: SNAP_ANGLE_STEP } : void 0;
23
+ const snap = spanSnap(ctx.deps.snap, constrain, parent === null ? {} : { parent });
21
24
  const behaviors = opts?.behaviors ?? [];
22
25
  const readers = gestureReaders(ctx.deps);
23
26
  const origin = snap.start({
@@ -51,6 +54,7 @@ function beginInsert(ctx, opts) {
51
54
  behaviors,
52
55
  gestureCtx,
53
56
  scene: ctx.deps.scene,
57
+ parent,
54
58
  applyOps: ctx.deps.applyOps,
55
59
  selection
56
60
  },
@@ -1 +1 @@
1
- {"version":3,"file":"session.js","names":[],"sources":["../../../../src/interactions/actions/insert/session.ts"],"sourcesContent":["import type { BindingOpts, DragSample, InvocationCtx } from '@weasel-js/routing';\nimport { resolveParams } from '@weasel-js/routing';\nimport { SNAP_ANGLE_STEP, snapMods } from 'features/snap/roles';\nimport { spanSnap, type SpanSnap } from 'features/snap/spanSnap';\nimport { pointerStateOf } from '../pointerState';\nimport type { Op } from 'core/ops/types';\nimport type { NodeId, Scene } from 'core/scene/types';\nimport type { SelectionApi } from 'core/selection/useSelection';\nimport { gestureReaders, type GestureReaders } from '../../gestures/shared/screenTolerance';\nimport type { GestureContext, InsertBehavior, InsertPoint } from '../../gestures/types';\nimport type { InsertDep, TextEditDep } from '../depSchema';\nimport { insertKind } from './shape';\n\n/** The key an insert's single gesture point rides under in the behaviors'\n * `draggedIds` / `origin` / `current` — insert has no node id yet. */\nexport const GESTURE_KEY = 'gesture';\n\n/** What an insert captured at press. Nothing here changes during the drag.\n * The deps are captured because the dispatcher builds the deps bag once, on\n * `start`: every later pump event carries `deps: {}`. */\nexport interface InsertSession {\n readonly dep: InsertDep;\n /** For the text kind's drop-into-the-caret step. */\n readonly textEdit: TextEditDep | undefined;\n /** Snaps the drag's start and current point, so the live preview and the\n * committed geometry agree. Freehand pencil samples are deliberately NOT\n * snapped — a grid-quantized freehand trail is a staircase, not a stroke. */\n readonly snap: SpanSnap;\n /** The active binding's opts — re-resolved on every read so thunked\n * params see the latest tool state (e.g. polygon `sides` after ArrowUp). */\n readonly opts: BindingOpts | undefined;\n /** What was selected before the draw cleared it, to put back on cancel. */\n readonly priorSelection: readonly NodeId[];\n /** Behaviors from `opts.behaviors`; empty when none were bound. */\n readonly behaviors: readonly InsertBehavior<unknown>[];\n /** Reused gesture context handed to behaviors. Its `origin` holds the\n * start point under {@link GESTURE_KEY}, after `onStart` shaped it. */\n readonly gestureCtx: GestureContext<unknown>;\n /** For committing a behavior's `Op[]`. */\n readonly scene: Scene<unknown, string, unknown> | undefined;\n readonly applyOps: ((ops: Op[], label: string) => void) | undefined;\n readonly selection: SelectionApi | undefined;\n}\n\n/** What the latest pump event left. Replaced, not mutated, by the next. */\nexport interface InsertFrame {\n /** The raw (unsnapped) pointer in world space. */\n readonly pointer: InsertPoint;\n /** Pointer trail accumulated by the dispatcher in world space; pencil-kind\n * commits read it. */\n readonly points: ReadonlyArray<DragSample> | null;\n /** Alt inverts the binding's nominal `originMode` (corner ⇄ center), so\n * pressing or releasing it mid-drag flips the preview and the commit\n * without the dispatcher re-routing to another binding. */\n readonly altHeld: boolean;\n /** The endpoints after the snap session and the behaviors. */\n readonly shaped: { start: InsertPoint; current: InsertPoint };\n}\n\n/** Capture an insert at press. Null with no `insert` dep. Clears the\n * selection and runs each behavior's `onStart`. */\nexport function beginInsert(\n ctx: InvocationCtx,\n opts: BindingOpts | undefined,\n): { session: InsertSession; readers: GestureReaders; frame: InsertFrame } | null {\n const dep = ctx.deps.insert;\n if (!dep) return null;\n\n // Starting a draw retires any prior selection — the lingering halo\n // around an unrelated node while the user is drawing a new shape is\n // just visual noise, and it primes the UX bug where a drag that\n // continues over the selected node would otherwise drive the move\n // action via fall-through. The clear is unconditional: the user has\n // committed to \"I'm making a new thing\" by engaging a creation tool.\n const selection = ctx.deps.selection;\n const priorSelection = selection ? [...selection.get()] : [];\n if (selection && priorSelection.length > 0) {\n selection.clear();\n }\n\n const snap = spanSnap(ctx.deps.snap, () =>\n insertKind(resolveParams(opts?.params)) === 'line' ? { step: SNAP_ANGLE_STEP } : undefined);\n const behaviors = (opts?.behaviors ?? []) as InsertBehavior<unknown>[];\n const readers = gestureReaders(ctx.deps);\n const origin = snap.start({ x: ctx.world.x, y: ctx.world.y }, snapMods(ctx)).point;\n const gestureCtx: GestureContext<unknown> = {\n draggedIds: [GESTURE_KEY],\n origin: new Map<string, unknown>([[GESTURE_KEY, origin]]),\n current: new Map<string, unknown>([[GESTURE_KEY, origin]]),\n snap: null,\n modifiers: { ...ctx.modifiers },\n pointer: pointerStateOf(ctx.world, ctx),\n view: readers.view(),\n plane: readers.plane(),\n kitSettings: readers.kitSettings,\n // No node exists to adapt until commit; insert behaviors read points.\n adapter: undefined as unknown as GestureContext<unknown>['adapter'],\n scratch: {},\n };\n for (const b of behaviors) b.onStart?.(gestureCtx);\n // A snap target in range outranks a behavior's own snapping.\n if (snap.startHeld()) gestureCtx.origin.set(GESTURE_KEY, origin);\n const startPoint = gestureCtx.origin.get(GESTURE_KEY) as InsertPoint;\n snap.anchor(startPoint);\n\n const session: InsertSession = {\n dep,\n textEdit: ctx.deps.textEdit,\n snap,\n opts,\n priorSelection,\n behaviors,\n gestureCtx,\n scene: ctx.deps.scene,\n applyOps: ctx.deps.applyOps,\n selection,\n };\n const frame: InsertFrame = {\n pointer: { x: ctx.world.x, y: ctx.world.y },\n points: ctx.drag?.points ?? null,\n altHeld: ctx.modifiers.alt,\n shaped: { start: startPoint, current: startPoint },\n };\n return { session, readers, frame };\n}\n"],"mappings":";;;;;;;;;;AAeA,IAAa,cAAc;;;AA8C3B,SAAgB,YACd,KACA,MACgF;CAChF,MAAM,MAAM,IAAI,KAAK;CACrB,IAAI,CAAC,KAAK,OAAO;CAQjB,MAAM,YAAY,IAAI,KAAK;CAC3B,MAAM,iBAAiB,YAAY,CAAC,GAAG,UAAU,IAAI,CAAC,IAAI,CAAC;CAC3D,IAAI,aAAa,eAAe,SAAS,GACvC,UAAU,MAAM;CAGlB,MAAM,OAAO,SAAS,IAAI,KAAK,YAC7B,WAAW,cAAc,MAAM,MAAM,CAAC,MAAM,SAAS,EAAE,MAAM,gBAAgB,IAAI,MAAS;CAC5F,MAAM,YAAa,MAAM,aAAa,CAAC;CACvC,MAAM,UAAU,eAAe,IAAI,IAAI;CACvC,MAAM,SAAS,KAAK,MAAM;EAAE,GAAG,IAAI,MAAM;EAAG,GAAG,IAAI,MAAM;CAAE,GAAG,SAAS,GAAG,CAAC,CAAC,CAAC;CAC7E,MAAM,aAAsC;EAC1C,YAAY,CAAC,WAAW;EACxB,wBAAQ,IAAI,IAAqB,CAAC,CAAC,aAAa,MAAM,CAAC,CAAC;EACxD,yBAAS,IAAI,IAAqB,CAAC,CAAC,aAAa,MAAM,CAAC,CAAC;EACzD,MAAM;EACN,WAAW,EAAE,GAAG,IAAI,UAAU;EAC9B,SAAS,eAAe,IAAI,OAAO,GAAG;EACtC,MAAM,QAAQ,KAAK;EACnB,OAAO,QAAQ,MAAM;EACrB,aAAa,QAAQ;EAErB,SAAS;EACT,SAAS,CAAC;CACZ;CACA,KAAK,MAAM,KAAK,WAAW,EAAE,UAAU,UAAU;CAEjD,IAAI,KAAK,UAAU,GAAG,WAAW,OAAO,IAAI,aAAa,MAAM;CAC/D,MAAM,aAAa,WAAW,OAAO,IAAI,WAAW;CACpD,KAAK,OAAO,UAAU;CAoBtB,OAAO;EAAE;GAjBP;GACA,UAAU,IAAI,KAAK;GACnB;GACA;GACA;GACA;GACA;GACA,OAAO,IAAI,KAAK;GAChB,UAAU,IAAI,KAAK;GACnB;EAQO;EAAS;EAAS;GALzB,SAAS;IAAE,GAAG,IAAI,MAAM;IAAG,GAAG,IAAI,MAAM;GAAE;GAC1C,QAAQ,IAAI,MAAM,UAAU;GAC5B,SAAS,IAAI,UAAU;GACvB,QAAQ;IAAE,OAAO;IAAY,SAAS;GAAW;EAExB;CAAM;AACnC"}
1
+ {"version":3,"file":"session.js","names":[],"sources":["../../../../src/interactions/actions/insert/session.ts"],"sourcesContent":["import type { BindingOpts, DragSample, InvocationCtx } from '@weasel-js/routing';\nimport { resolveParams } from '@weasel-js/routing';\nimport { SNAP_ANGLE_STEP, snapMods } from 'features/snap/roles';\nimport { spanSnap, type SpanSnap } from 'features/snap/spanSnap';\nimport { pointerStateOf } from '../pointerState';\nimport type { Op } from 'core/ops/types';\nimport type { NodeId, Scene } from 'core/scene/types';\nimport type { SelectionApi } from 'core/selection/useSelection';\nimport { gestureReaders, type GestureReaders } from '../../gestures/shared/screenTolerance';\nimport type { GestureContext, InsertBehavior, InsertPoint } from '../../gestures/types';\nimport type { InsertDep, TextEditDep } from '../depSchema';\nimport { insertParent } from './parent';\nimport { insertKind } from './shape';\n\n/** The key an insert's single gesture point rides under in the behaviors'\n * `draggedIds` / `origin` / `current` — insert has no node id yet. */\nexport const GESTURE_KEY = 'gesture';\n\n/** What an insert captured at press. Nothing here changes during the drag.\n * The deps are captured because the dispatcher builds the deps bag once, on\n * `start`: every later pump event carries `deps: {}`. */\nexport interface InsertSession {\n readonly dep: InsertDep;\n /** For the text kind's drop-into-the-caret step. */\n readonly textEdit: TextEditDep | undefined;\n /** Snaps the drag's start and current point, so the live preview and the\n * committed geometry agree. Freehand pencil samples are deliberately NOT\n * snapped — a grid-quantized freehand trail is a staircase, not a stroke. */\n readonly snap: SpanSnap;\n /** The active binding's opts — re-resolved on every read so thunked\n * params see the latest tool state (e.g. polygon `sides` after ArrowUp). */\n readonly opts: BindingOpts | undefined;\n /** What was selected before the draw cleared it, to put back on cancel. */\n readonly priorSelection: readonly NodeId[];\n /** Behaviors from `opts.behaviors`; empty when none were bound. */\n readonly behaviors: readonly InsertBehavior<unknown>[];\n /** Reused gesture context handed to behaviors. Its `origin` holds the\n * start point under {@link GESTURE_KEY}, after `onStart` shaped it. */\n readonly gestureCtx: GestureContext<unknown>;\n /** For committing a behavior's `Op[]`. */\n readonly scene: Scene<unknown, string, unknown> | undefined;\n /** The container the node lands in; null for the top of the tree. */\n readonly parent: NodeId | null;\n readonly applyOps: ((ops: Op[], label: string) => void) | undefined;\n readonly selection: SelectionApi | undefined;\n}\n\n/** What the latest pump event left. Replaced, not mutated, by the next. */\nexport interface InsertFrame {\n /** The raw (unsnapped) pointer in world space. */\n readonly pointer: InsertPoint;\n /** Pointer trail accumulated by the dispatcher in world space; pencil-kind\n * commits read it. */\n readonly points: ReadonlyArray<DragSample> | null;\n /** Alt inverts the binding's nominal `originMode` (corner ⇄ center), so\n * pressing or releasing it mid-drag flips the preview and the commit\n * without the dispatcher re-routing to another binding. */\n readonly altHeld: boolean;\n /** The endpoints after the snap session and the behaviors. */\n readonly shaped: { start: InsertPoint; current: InsertPoint };\n}\n\n/** Capture an insert at press. Null with no `insert` dep. Clears the\n * selection and runs each behavior's `onStart`. */\nexport function beginInsert(\n ctx: InvocationCtx,\n opts: BindingOpts | undefined,\n): { session: InsertSession; readers: GestureReaders; frame: InsertFrame } | null {\n const dep = ctx.deps.insert;\n if (!dep) return null;\n\n // Starting a draw retires any prior selection — the lingering halo\n // around an unrelated node while the user is drawing a new shape is\n // just visual noise, and it primes the UX bug where a drag that\n // continues over the selected node would otherwise drive the move\n // action via fall-through. The clear is unconditional: the user has\n // committed to \"I'm making a new thing\" by engaging a creation tool.\n const selection = ctx.deps.selection;\n const priorSelection = selection ? [...selection.get()] : [];\n if (selection && priorSelection.length > 0) {\n selection.clear();\n }\n\n const parent = insertParent(ctx.deps.scene, ctx.deps.insertInto?.get());\n const constrain = () => (insertKind(resolveParams(opts?.params)) === 'line' ? { step: SNAP_ANGLE_STEP } : undefined);\n const snap = spanSnap(ctx.deps.snap, constrain, parent === null ? {} : { parent });\n const behaviors = (opts?.behaviors ?? []) as InsertBehavior<unknown>[];\n const readers = gestureReaders(ctx.deps);\n const origin = snap.start({ x: ctx.world.x, y: ctx.world.y }, snapMods(ctx)).point;\n const gestureCtx: GestureContext<unknown> = {\n draggedIds: [GESTURE_KEY],\n origin: new Map<string, unknown>([[GESTURE_KEY, origin]]),\n current: new Map<string, unknown>([[GESTURE_KEY, origin]]),\n snap: null,\n modifiers: { ...ctx.modifiers },\n pointer: pointerStateOf(ctx.world, ctx),\n view: readers.view(),\n plane: readers.plane(),\n kitSettings: readers.kitSettings,\n // No node exists to adapt until commit; insert behaviors read points.\n adapter: undefined as unknown as GestureContext<unknown>['adapter'],\n scratch: {},\n };\n for (const b of behaviors) b.onStart?.(gestureCtx);\n // A snap target in range outranks a behavior's own snapping.\n if (snap.startHeld()) gestureCtx.origin.set(GESTURE_KEY, origin);\n const startPoint = gestureCtx.origin.get(GESTURE_KEY) as InsertPoint;\n snap.anchor(startPoint);\n\n const session: InsertSession = {\n dep,\n textEdit: ctx.deps.textEdit,\n snap,\n opts,\n priorSelection,\n behaviors,\n gestureCtx,\n scene: ctx.deps.scene,\n parent,\n applyOps: ctx.deps.applyOps,\n selection,\n };\n const frame: InsertFrame = {\n pointer: { x: ctx.world.x, y: ctx.world.y },\n points: ctx.drag?.points ?? null,\n altHeld: ctx.modifiers.alt,\n shaped: { start: startPoint, current: startPoint },\n };\n return { session, readers, frame };\n}\n"],"mappings":";;;;;;;;;;;AAgBA,IAAa,cAAc;;;AAgD3B,SAAgB,YACd,KACA,MACgF;CAChF,MAAM,MAAM,IAAI,KAAK;CACrB,IAAI,CAAC,KAAK,OAAO;CAQjB,MAAM,YAAY,IAAI,KAAK;CAC3B,MAAM,iBAAiB,YAAY,CAAC,GAAG,UAAU,IAAI,CAAC,IAAI,CAAC;CAC3D,IAAI,aAAa,eAAe,SAAS,GACvC,UAAU,MAAM;CAGlB,MAAM,SAAS,aAAa,IAAI,KAAK,OAAO,IAAI,KAAK,YAAY,IAAI,CAAC;CACtE,MAAM,kBAAmB,WAAW,cAAc,MAAM,MAAM,CAAC,MAAM,SAAS,EAAE,MAAM,gBAAgB,IAAI;CAC1G,MAAM,OAAO,SAAS,IAAI,KAAK,MAAM,WAAW,WAAW,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC;CACjF,MAAM,YAAa,MAAM,aAAa,CAAC;CACvC,MAAM,UAAU,eAAe,IAAI,IAAI;CACvC,MAAM,SAAS,KAAK,MAAM;EAAE,GAAG,IAAI,MAAM;EAAG,GAAG,IAAI,MAAM;CAAE,GAAG,SAAS,GAAG,CAAC,CAAC,CAAC;CAC7E,MAAM,aAAsC;EAC1C,YAAY,CAAC,WAAW;EACxB,wBAAQ,IAAI,IAAqB,CAAC,CAAC,aAAa,MAAM,CAAC,CAAC;EACxD,yBAAS,IAAI,IAAqB,CAAC,CAAC,aAAa,MAAM,CAAC,CAAC;EACzD,MAAM;EACN,WAAW,EAAE,GAAG,IAAI,UAAU;EAC9B,SAAS,eAAe,IAAI,OAAO,GAAG;EACtC,MAAM,QAAQ,KAAK;EACnB,OAAO,QAAQ,MAAM;EACrB,aAAa,QAAQ;EAErB,SAAS;EACT,SAAS,CAAC;CACZ;CACA,KAAK,MAAM,KAAK,WAAW,EAAE,UAAU,UAAU;CAEjD,IAAI,KAAK,UAAU,GAAG,WAAW,OAAO,IAAI,aAAa,MAAM;CAC/D,MAAM,aAAa,WAAW,OAAO,IAAI,WAAW;CACpD,KAAK,OAAO,UAAU;CAqBtB,OAAO;EAAE;GAlBP;GACA,UAAU,IAAI,KAAK;GACnB;GACA;GACA;GACA;GACA;GACA,OAAO,IAAI,KAAK;GAChB;GACA,UAAU,IAAI,KAAK;GACnB;EAQO;EAAS;EAAS;GALzB,SAAS;IAAE,GAAG,IAAI,MAAM;IAAG,GAAG,IAAI,MAAM;GAAE;GAC1C,QAAQ,IAAI,MAAM,UAAU;GAC5B,SAAS,IAAI,UAAU;GACvB,QAAQ;IAAE,OAAO;IAAY,SAAS;GAAW;EAExB;CAAM;AACnC"}
@@ -1,3 +1,4 @@
1
+ import { transformPreview } from "../transformFinish.js";
1
2
  import { closeGesture, runBehaviorCancel } from "../gestureLifecycle.js";
2
3
  import { inPlane, selectionLayer } from "../planeInput.js";
3
4
  import { beginMove } from "./session.js";
@@ -26,10 +27,13 @@ var moveAction = inPlane({
26
27
  id: "move",
27
28
  label: "Move",
28
29
  activeCursor: "move",
29
- defaultBinding: {
30
- kind: "drag",
31
- target: "selected-body"
32
- },
30
+ defaultBinding: [{
31
+ spec: {
32
+ kind: "drag",
33
+ target: "selected-body"
34
+ },
35
+ opts: { id: "move.drag" }
36
+ }],
33
37
  eligible: { capability: "transforms-selection" },
34
38
  modifierRoles: SNAP_ROLES,
35
39
  requires: [
@@ -40,10 +44,12 @@ var moveAction = inPlane({
40
44
  "applyOps",
41
45
  "geometryProjection",
42
46
  "nodeAtPoint",
47
+ "canDropInto",
43
48
  "view",
44
49
  "boundsIncludeStroke",
45
50
  "kitSettings",
46
- "snap"
51
+ "snap",
52
+ "transformFollowers"
47
53
  ],
48
54
  invoker: {
49
55
  timing: "ongoing",
@@ -61,6 +67,7 @@ var moveAction = inPlane({
61
67
  const { session, readers } = begun;
62
68
  const subject = [...ctx.deps.selection?.get() ?? []];
63
69
  const hold = session.scene.overrides.hold();
70
+ const preview = transformPreview(ctx.deps, session.scene, () => frame.previews);
64
71
  let engaged = null;
65
72
  return {
66
73
  kind: "move",
@@ -79,7 +86,7 @@ var moveAction = inPlane({
79
86
  }
80
87
  engaged = moveCtx.world;
81
88
  frame = nextFrame(session, readers, moveCtx);
82
- hold.set(frame.previews);
89
+ hold.set(preview.poses());
83
90
  },
84
91
  onEnd(endCtx, reason) {
85
92
  let committed = false;
@@ -106,8 +113,8 @@ var moveAction = inPlane({
106
113
  }, committed);
107
114
  }
108
115
  },
109
- previewIds: () => frame.previews.keys(),
110
- previewPose: (id) => frame.previews.get(id) ?? null,
116
+ previewIds: preview.previewIds,
117
+ previewData: preview.previewData,
111
118
  previewOpaqueIds: () => frame.opaque.size === 0 ? null : frame.opaque
112
119
  };
113
120
  }
@@ -1 +1 @@
1
- {"version":3,"file":"action.js","names":[],"sources":["../../../../src/interactions/actions/move/action.ts"],"sourcesContent":["import type { Action } from '@weasel-js/routing';\nimport type { InvocationCtx, OngoingHandle, BindingOpts } from '@weasel-js/routing';\nimport { pastDragThreshold } from '@weasel-js/routing';\nimport type { NodeId } from 'core/scene/types';\nimport { closeGesture, runBehaviorCancel } from '../gestureLifecycle';\nimport { inPlane, selectionLayer } from '../planeInput';\nimport { beginMove, type MoveFrame, type ReparentOnDrop } from './session';\nimport { nextFrame } from './frame';\nimport { commitMove } from './commit';\nimport { recordTransform } from '../transform-again/memory';\nimport { SNAP_ROLES } from 'features/snap/roles';\nexport type { ReparentOnDrop };\n\n/**\n * Drag-translates the selection.\n *\n * Each frame's poses go to the scene's ephemeral override table, not the\n * document: `Scene.setPose` records an undo entry per call, and the overrides\n * are what let a node deriving its geometry from a dragged one follow the\n * drag. Release commits one batch — at most one undo entry, none when the\n * binding's params make it transient — and cancel drops the overrides.\n *\n * Behaviors from the binding's `opts.behaviors` fold into each frame; on\n * release the first non-`undefined` answer wins (`Op[]` commits, `null`\n * aborts). `beginMove` appends the action's own two: a layout drop and\n * reparent-on-drop.\n */\nexport const moveAction: Action & { requires: string[] } = inPlane({\n id: 'move',\n label: 'Move',\n // No hover `cursor`: pointing at a node shouldn't preemptively promise a move.\n activeCursor: 'move',\n // Ambient default targets `selected-body`, not a bare `{ kind: 'drag' }`,\n // which catches every drag in ambient scope and bleeds the move into\n // drawing-tool gestures wherever the higher-priority active match falls\n // through.\n defaultBinding: { kind: 'drag', target: 'selected-body' },\n eligible: { capability: 'transforms-selection' },\n modifierRoles: SNAP_ROLES,\n requires: ['selection', 'scene', 'poseDescriptor', 'layout', 'applyOps', 'geometryProjection', 'nodeAtPoint', 'view', 'boundsIncludeStroke', 'kitSettings', 'snap'],\n invoker: {\n timing: 'ongoing',\n start(ctx: InvocationCtx, opts?: BindingOpts): OngoingHandle {\n let frame: MoveFrame = { delta: { dx: 0, dy: 0 }, previews: new Map(), opaque: new Set() };\n const begun = beginMove(ctx, opts, () => frame);\n if (!begun) return {};\n const { session, readers } = begun;\n const subject = [...(ctx.deps.selection?.get() ?? [])] as string[];\n const hold = session.scene.overrides.hold();\n // Where the last move put the pointer, once the drag has passed its\n // threshold; null until then.\n let engaged: { x: number; y: number } | null = null;\n return {\n kind: 'move',\n onMove(moveCtx: InvocationCtx): void {\n if (!moveCtx.drag) return;\n if (!engaged) {\n const s = moveCtx.drag.screenDelta;\n if (s && !pastDragThreshold({ clientX: 0, clientY: 0 }, { clientX: s.x, clientY: s.y }, session.dragThresholdPx)) return;\n session.lifecycle.start(session.ids as unknown as string[]);\n }\n engaged = moveCtx.world;\n frame = nextFrame(session, readers, moveCtx);\n hold.set(frame.previews);\n },\n onEnd(endCtx: InvocationCtx, reason: 'commit' | 'cancel'): void {\n let committed = false;\n try {\n // A press that never traveled `dragThresholdPx` was never a move:\n // its behaviors started, so they are canceled, not asked to commit.\n if (reason === 'commit' && engaged) {\n committed = commitMove({\n session,\n delta: frame.delta,\n at: endCtx.drag ? endCtx.world : engaged,\n });\n if (committed) recordTransform(session.scene, { kind: 'translate', ...frame.delta }, subject);\n } else runBehaviorCancel(session.behaviors, session.gestureCtx);\n } finally {\n session.snap?.end();\n // After the commit, so no frame can paint the pre-drag pose between\n // the override going away and the document catching up.\n closeGesture({ hold, previews: frame.previews, behaviors: session.behaviors, ctx: session.gestureCtx, lifecycle: session.lifecycle }, committed);\n }\n },\n previewIds: () => frame.previews.keys(),\n previewPose: (id: string) => frame.previews.get(id as NodeId) ?? null,\n previewOpaqueIds: () => (frame.opaque.size === 0 ? null : frame.opaque),\n };\n },\n },\n /**\n * Always enabled: the dispatcher treats anything `!== true` as \"fall\n * through to the next-best match\", so a disabled reason here loses every\n * drag-on-selected-body to a lower-specificity binding (a shape tool's\n * insert drag).\n */\n enabled: () => true,\n}, selectionLayer);\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AA2BA,IAAa,aAA8C,QAAQ;CACjE,IAAI;CACJ,OAAO;CAEP,cAAc;CAKd,gBAAgB;EAAE,MAAM;EAAQ,QAAQ;CAAgB;CACxD,UAAU,EAAE,YAAY,uBAAuB;CAC/C,eAAe;CACf,UAAU;EAAC;EAAa;EAAS;EAAkB;EAAU;EAAY;EAAsB;EAAe;EAAQ;EAAuB;EAAe;CAAM;CAClK,SAAS;EACP,QAAQ;EACR,MAAM,KAAoB,MAAmC;GAC3D,IAAI,QAAmB;IAAE,OAAO;KAAE,IAAI;KAAG,IAAI;IAAE;IAAG,0BAAU,IAAI,IAAI;IAAG,wBAAQ,IAAI,IAAI;GAAE;GACzF,MAAM,QAAQ,UAAU,KAAK,YAAY,KAAK;GAC9C,IAAI,CAAC,OAAO,OAAO,CAAC;GACpB,MAAM,EAAE,SAAS,YAAY;GAC7B,MAAM,UAAU,CAAC,GAAI,IAAI,KAAK,WAAW,IAAI,KAAK,CAAC,CAAE;GACrD,MAAM,OAAO,QAAQ,MAAM,UAAU,KAAK;GAG1C,IAAI,UAA2C;GAC/C,OAAO;IACL,MAAM;IACN,OAAO,SAA8B;KACnC,IAAI,CAAC,QAAQ,MAAM;KACnB,IAAI,CAAC,SAAS;MACZ,MAAM,IAAI,QAAQ,KAAK;MACvB,IAAI,KAAK,CAAC,kBAAkB;OAAE,SAAS;OAAG,SAAS;MAAE,GAAG;OAAE,SAAS,EAAE;OAAG,SAAS,EAAE;MAAE,GAAG,QAAQ,eAAe,GAAG;MAClH,QAAQ,UAAU,MAAM,QAAQ,GAA0B;KAC5D;KACA,UAAU,QAAQ;KAClB,QAAQ,UAAU,SAAS,SAAS,OAAO;KAC3C,KAAK,IAAI,MAAM,QAAQ;IACzB;IACA,MAAM,QAAuB,QAAmC;KAC9D,IAAI,YAAY;KAChB,IAAI;MAGF,IAAI,WAAW,YAAY,SAAS;OAClC,YAAY,WAAW;QACrB;QACA,OAAO,MAAM;QACb,IAAI,OAAO,OAAO,OAAO,QAAQ;OACnC,CAAC;OACD,IAAI,WAAW,gBAAgB,QAAQ,OAAO;QAAE,MAAM;QAAa,GAAG,MAAM;OAAM,GAAG,OAAO;MAC9F,OAAO,kBAAkB,QAAQ,WAAW,QAAQ,UAAU;KAChE,UAAU;MACR,QAAQ,MAAM,IAAI;MAGlB,aAAa;OAAE;OAAM,UAAU,MAAM;OAAU,WAAW,QAAQ;OAAW,KAAK,QAAQ;OAAY,WAAW,QAAQ;MAAU,GAAG,SAAS;KACjJ;IACF;IACA,kBAAkB,MAAM,SAAS,KAAK;IACtC,cAAc,OAAe,MAAM,SAAS,IAAI,EAAY,KAAK;IACjE,wBAAyB,MAAM,OAAO,SAAS,IAAI,OAAO,MAAM;GAClE;EACF;CACF;;;;;;;CAOA,eAAe;AACjB,GAAG,cAAc"}
1
+ {"version":3,"file":"action.js","names":[],"sources":["../../../../src/interactions/actions/move/action.ts"],"sourcesContent":["import type { Action } from '@weasel-js/routing';\nimport type { InvocationCtx, OngoingHandle, BindingOpts } from '@weasel-js/routing';\nimport { transformPreview } from '../transformFinish';\nimport { pastDragThreshold } from '@weasel-js/routing';\nimport { closeGesture, runBehaviorCancel } from '../gestureLifecycle';\nimport { inPlane, selectionLayer } from '../planeInput';\nimport { beginMove, type MoveFrame, type ReparentOnDrop } from './session';\nimport { nextFrame } from './frame';\nimport { commitMove } from './commit';\nimport { recordTransform } from '../transform-again/memory';\nimport { SNAP_ROLES } from 'features/snap/roles';\nexport type { ReparentOnDrop };\n\n/**\n * Drag-translates the selection.\n *\n * Each frame's poses go to the scene's ephemeral override table, not the\n * document: `Scene.setPose` records an undo entry per call, and the overrides\n * are what let a node deriving its geometry from a dragged one follow the\n * drag. Release commits one batch — at most one undo entry, none when the\n * binding's params make it transient — and cancel drops the overrides.\n *\n * Behaviors from the binding's `opts.behaviors` fold into each frame; on\n * release the first non-`undefined` answer wins (`Op[]` commits, `null`\n * aborts). `beginMove` appends the action's own two: a layout drop and\n * reparent-on-drop.\n */\nexport const moveAction: Action & { requires: string[] } = inPlane({\n id: 'move',\n label: 'Move',\n // No hover `cursor`: pointing at a node shouldn't preemptively promise a move.\n activeCursor: 'move',\n // Ambient default targets `selected-body`, not a bare `{ kind: 'drag' }`,\n // which catches every drag in ambient scope and bleeds the move into\n // drawing-tool gestures wherever the higher-priority active match falls\n // through.\n defaultBinding: [{ spec: { kind: 'drag', target: 'selected-body' }, opts: { id: 'move.drag' } }],\n eligible: { capability: 'transforms-selection' },\n modifierRoles: SNAP_ROLES,\n requires: ['selection', 'scene', 'poseDescriptor', 'layout', 'applyOps', 'geometryProjection', 'nodeAtPoint', 'canDropInto', 'view', 'boundsIncludeStroke', 'kitSettings', 'snap', 'transformFollowers'],\n invoker: {\n timing: 'ongoing',\n start(ctx: InvocationCtx, opts?: BindingOpts): OngoingHandle {\n let frame: MoveFrame = { delta: { dx: 0, dy: 0 }, previews: new Map(), opaque: new Set() };\n const begun = beginMove(ctx, opts, () => frame);\n if (!begun) return {};\n const { session, readers } = begun;\n const subject = [...(ctx.deps.selection?.get() ?? [])] as string[];\n const hold = session.scene.overrides.hold();\n const preview = transformPreview(ctx.deps, session.scene, () => frame.previews);\n // Where the last move put the pointer, once the drag has passed its\n // threshold; null until then.\n let engaged: { x: number; y: number } | null = null;\n return {\n kind: 'move',\n onMove(moveCtx: InvocationCtx): void {\n if (!moveCtx.drag) return;\n if (!engaged) {\n const s = moveCtx.drag.screenDelta;\n if (s && !pastDragThreshold({ clientX: 0, clientY: 0 }, { clientX: s.x, clientY: s.y }, session.dragThresholdPx)) return;\n session.lifecycle.start(session.ids as unknown as string[]);\n }\n engaged = moveCtx.world;\n frame = nextFrame(session, readers, moveCtx);\n hold.set(preview.poses());\n },\n onEnd(endCtx: InvocationCtx, reason: 'commit' | 'cancel'): void {\n let committed = false;\n try {\n // A press that never traveled `dragThresholdPx` was never a move:\n // its behaviors started, so they are canceled, not asked to commit.\n if (reason === 'commit' && engaged) {\n committed = commitMove({\n session,\n delta: frame.delta,\n at: endCtx.drag ? endCtx.world : engaged,\n });\n if (committed) recordTransform(session.scene, { kind: 'translate', ...frame.delta }, subject);\n } else runBehaviorCancel(session.behaviors, session.gestureCtx);\n } finally {\n session.snap?.end();\n // After the commit, so no frame can paint the pre-drag pose between\n // the override going away and the document catching up.\n closeGesture({ hold, previews: frame.previews, behaviors: session.behaviors, ctx: session.gestureCtx, lifecycle: session.lifecycle }, committed);\n }\n },\n previewIds: preview.previewIds,\n previewData: preview.previewData,\n previewOpaqueIds: () => (frame.opaque.size === 0 ? null : frame.opaque),\n };\n },\n },\n /**\n * Always enabled: the dispatcher treats anything `!== true` as \"fall\n * through to the next-best match\", so a disabled reason here loses every\n * drag-on-selected-body to a lower-specificity binding (a shape tool's\n * insert drag).\n */\n enabled: () => true,\n}, selectionLayer);\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AA2BA,IAAa,aAA8C,QAAQ;CACjE,IAAI;CACJ,OAAO;CAEP,cAAc;CAKd,gBAAgB,CAAC;EAAE,MAAM;GAAE,MAAM;GAAQ,QAAQ;EAAgB;EAAG,MAAM,EAAE,IAAI,YAAY;CAAE,CAAC;CAC/F,UAAU,EAAE,YAAY,uBAAuB;CAC/C,eAAe;CACf,UAAU;EAAC;EAAa;EAAS;EAAkB;EAAU;EAAY;EAAsB;EAAe;EAAe;EAAQ;EAAuB;EAAe;EAAQ;CAAoB;CACvM,SAAS;EACP,QAAQ;EACR,MAAM,KAAoB,MAAmC;GAC3D,IAAI,QAAmB;IAAE,OAAO;KAAE,IAAI;KAAG,IAAI;IAAE;IAAG,0BAAU,IAAI,IAAI;IAAG,wBAAQ,IAAI,IAAI;GAAE;GACzF,MAAM,QAAQ,UAAU,KAAK,YAAY,KAAK;GAC9C,IAAI,CAAC,OAAO,OAAO,CAAC;GACpB,MAAM,EAAE,SAAS,YAAY;GAC7B,MAAM,UAAU,CAAC,GAAI,IAAI,KAAK,WAAW,IAAI,KAAK,CAAC,CAAE;GACrD,MAAM,OAAO,QAAQ,MAAM,UAAU,KAAK;GAC1C,MAAM,UAAU,iBAAiB,IAAI,MAAM,QAAQ,aAAa,MAAM,QAAQ;GAG9E,IAAI,UAA2C;GAC/C,OAAO;IACL,MAAM;IACN,OAAO,SAA8B;KACnC,IAAI,CAAC,QAAQ,MAAM;KACnB,IAAI,CAAC,SAAS;MACZ,MAAM,IAAI,QAAQ,KAAK;MACvB,IAAI,KAAK,CAAC,kBAAkB;OAAE,SAAS;OAAG,SAAS;MAAE,GAAG;OAAE,SAAS,EAAE;OAAG,SAAS,EAAE;MAAE,GAAG,QAAQ,eAAe,GAAG;MAClH,QAAQ,UAAU,MAAM,QAAQ,GAA0B;KAC5D;KACA,UAAU,QAAQ;KAClB,QAAQ,UAAU,SAAS,SAAS,OAAO;KAC3C,KAAK,IAAI,QAAQ,MAAM,CAAC;IAC1B;IACA,MAAM,QAAuB,QAAmC;KAC9D,IAAI,YAAY;KAChB,IAAI;MAGF,IAAI,WAAW,YAAY,SAAS;OAClC,YAAY,WAAW;QACrB;QACA,OAAO,MAAM;QACb,IAAI,OAAO,OAAO,OAAO,QAAQ;OACnC,CAAC;OACD,IAAI,WAAW,gBAAgB,QAAQ,OAAO;QAAE,MAAM;QAAa,GAAG,MAAM;OAAM,GAAG,OAAO;MAC9F,OAAO,kBAAkB,QAAQ,WAAW,QAAQ,UAAU;KAChE,UAAU;MACR,QAAQ,MAAM,IAAI;MAGlB,aAAa;OAAE;OAAM,UAAU,MAAM;OAAU,WAAW,QAAQ;OAAW,KAAK,QAAQ;OAAY,WAAW,QAAQ;MAAU,GAAG,SAAS;KACjJ;IACF;IACA,YAAY,QAAQ;IACpB,aAAa,QAAQ;IACrB,wBAAyB,MAAM,OAAO,SAAS,IAAI,OAAO,MAAM;GAClE;EACF;CACF;;;;;;;CAOA,eAAe;AACjB,GAAG,cAAc"}
@@ -24,7 +24,6 @@ function layoutDrop(move) {
24
24
  return {
25
25
  onMove(ctx, proposed) {
26
26
  drop = null;
27
- if (proposed.kind !== "translate") return;
28
27
  const session = move.session();
29
28
  drop = runDropPass(session, {
30
29
  dx: proposed.dx,
@@ -1 +1 @@
1
- {"version":3,"file":"layoutDrop.js","names":[],"sources":["../../../../../src/interactions/actions/move/behaviors/layoutDrop.ts"],"sourcesContent":["import type { Op } from 'core/ops/types';\nimport type { NodeId } from 'core/scene/types';\nimport type { BehaviorResult, MoveBehavior } from '../../../gestures/types';\nimport { layoutDropOps } from '../commit/layoutDrop';\nimport { layoutReleaseOps } from '../commit/layoutRelease';\nimport { runDropPass } from '../layout/dropPass';\nimport { landReleased, releasedPoses, stepGlide, type Released } from '../layout/glide';\nimport type { DropPass } from '../layout/types';\nimport type { MoveGesture } from '../session';\n\n/**\n * The move behavior that drops the selection into the layout container under\n * it. Each move it resolves the drop and shows the siblings making room; on\n * release it answers with the container's `commitDrop`, or, outside every\n * container, with what the source layouts' `releaseDrop` and the exits decide.\n *\n * Built by the move action for one drag, after the binding's own behaviors, and\n * only when the `layout` dep is present.\n */\nexport function layoutDrop(move: MoveGesture): MoveBehavior<unknown> {\n // This frame's pass; reset by every move, a throwing one included.\n let drop: DropPass | null = null;\n const gliding = new Set<NodeId>();\n let released: Map<NodeId, Released> | null = null;\n // Before the commit: where each dragged id is shown as the gesture closes.\n const noteReleased = (): void => {\n const session = move.session();\n if (session.layout?.reflow) released = releasedPoses(session, move.frame().previews);\n };\n\n return {\n onMove(ctx, proposed): BehaviorResult<unknown> | void {\n drop = null;\n if (proposed.kind !== 'translate') return;\n const session = move.session();\n drop = runDropPass(\n session,\n { dx: proposed.dx, dy: proposed.dy },\n { x: ctx.pointer.worldX, y: ctx.pointer.worldY },\n );\n const opaque = drop?.pass?.reflowIds;\n const reflow = session.layout?.reflow;\n if (!reflow) return { poses: drop?.reflow, opaque };\n stepGlide(reflow, gliding, drop?.reflow ?? new Map());\n return { opaque };\n },\n\n onEnd(_ctx, end): Op[] | null | void {\n noteReleased();\n if (end.answered) return;\n const session = move.session();\n const { delta } = move.frame();\n // No-op if no movement (sub-threshold drag or zero delta).\n if (delta.dx === 0 && delta.dy === 0) return;\n // A drop or a release that claims the selection and writes nothing\n // commits nothing: the translate must not run in its place.\n const orAbort = (ops: Op[]): Op[] | null => (ops.length > 0 ? ops : null);\n // Layout drop commit — takes precedence over reparent-on-drop when a\n // layout container accepted the drag this gesture. One placement per\n // dragged child, replayed in the order the preview resolved them.\n // TODO: geometryProjection for drop-reflow — left pose-only because the\n // reflow distributes per-child poses with no single global delta; not\n // exercised by the geometry contract gate.\n if (drop?.pass) return orAbort(layoutDropOps(session, drop.pass));\n const release = layoutReleaseOps(session, delta, drop?.dropCenter ?? null);\n return release === undefined ? undefined : orAbort(release);\n },\n\n onCancel: noteReleased,\n\n onSettled(): void {\n const session = move.session();\n const reflow = session.layout?.reflow;\n // After the commit: each glide settles onto the pose the document now\n // holds, or back home on a cancel — the dragged ids from where they\n // were let go.\n if (reflow) {\n for (const id of gliding) reflow.settle(id as string);\n landReleased(session, reflow, released ?? new Map());\n }\n gliding.clear();\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;AAmBA,SAAgB,WAAW,MAA0C;CAEnE,IAAI,OAAwB;CAC5B,MAAM,0BAAU,IAAI,IAAY;CAChC,IAAI,WAAyC;CAE7C,MAAM,qBAA2B;EAC/B,MAAM,UAAU,KAAK,QAAQ;EAC7B,IAAI,QAAQ,QAAQ,QAAQ,WAAW,cAAc,SAAS,KAAK,MAAM,CAAC,CAAC,QAAQ;CACrF;CAEA,OAAO;EACL,OAAO,KAAK,UAA0C;GACpD,OAAO;GACP,IAAI,SAAS,SAAS,aAAa;GACnC,MAAM,UAAU,KAAK,QAAQ;GAC7B,OAAO,YACL,SACA;IAAE,IAAI,SAAS;IAAI,IAAI,SAAS;GAAG,GACnC;IAAE,GAAG,IAAI,QAAQ;IAAQ,GAAG,IAAI,QAAQ;GAAO,CACjD;GACA,MAAM,SAAS,MAAM,MAAM;GAC3B,MAAM,SAAS,QAAQ,QAAQ;GAC/B,IAAI,CAAC,QAAQ,OAAO;IAAE,OAAO,MAAM;IAAQ;GAAO;GAClD,UAAU,QAAQ,SAAS,MAAM,0BAAU,IAAI,IAAI,CAAC;GACpD,OAAO,EAAE,OAAO;EAClB;EAEA,MAAM,MAAM,KAAyB;GACnC,aAAa;GACb,IAAI,IAAI,UAAU;GAClB,MAAM,UAAU,KAAK,QAAQ;GAC7B,MAAM,EAAE,UAAU,KAAK,MAAM;GAE7B,IAAI,MAAM,OAAO,KAAK,MAAM,OAAO,GAAG;GAGtC,MAAM,WAAW,QAA4B,IAAI,SAAS,IAAI,MAAM;GAOpE,IAAI,MAAM,MAAM,OAAO,QAAQ,cAAc,SAAS,KAAK,IAAI,CAAC;GAChE,MAAM,UAAU,iBAAiB,SAAS,OAAO,MAAM,cAAc,IAAI;GACzE,OAAO,YAAY,SAAY,SAAY,QAAQ,OAAO;EAC5D;EAEA,UAAU;EAEV,YAAkB;GAChB,MAAM,UAAU,KAAK,QAAQ;GAC7B,MAAM,SAAS,QAAQ,QAAQ;GAI/B,IAAI,QAAQ;IACV,KAAK,MAAM,MAAM,SAAS,OAAO,OAAO,EAAY;IACpD,aAAa,SAAS,QAAQ,4BAAY,IAAI,IAAI,CAAC;GACrD;GACA,QAAQ,MAAM;EAChB;CACF;AACF"}
1
+ {"version":3,"file":"layoutDrop.js","names":[],"sources":["../../../../../src/interactions/actions/move/behaviors/layoutDrop.ts"],"sourcesContent":["import type { Op } from 'core/ops/types';\nimport type { NodeId } from 'core/scene/types';\nimport type { BehaviorResult, MoveBehavior } from '../../../gestures/types';\nimport { layoutDropOps } from '../commit/layoutDrop';\nimport { layoutReleaseOps } from '../commit/layoutRelease';\nimport { runDropPass } from '../layout/dropPass';\nimport { landReleased, releasedPoses, stepGlide, type Released } from '../layout/glide';\nimport type { DropPass } from '../layout/types';\nimport type { MoveGesture } from '../session';\n\n/**\n * The move behavior that drops the selection into the layout container under\n * it. Each move it resolves the drop and shows the siblings making room; on\n * release it answers with the container's `commitDrop`, or, outside every\n * container, with what the source layouts' `releaseDrop` and the exits decide.\n *\n * Built by the move action for one drag, after the binding's own behaviors, and\n * only when the `layout` dep is present.\n */\nexport function layoutDrop(move: MoveGesture): MoveBehavior<unknown> {\n // This frame's pass; reset by every move, a throwing one included.\n let drop: DropPass | null = null;\n const gliding = new Set<NodeId>();\n let released: Map<NodeId, Released> | null = null;\n // Before the commit: where each dragged id is shown as the gesture closes.\n const noteReleased = (): void => {\n const session = move.session();\n if (session.layout?.reflow) released = releasedPoses(session, move.frame().previews);\n };\n\n return {\n onMove(ctx, proposed): BehaviorResult<unknown> | void {\n drop = null;\n const session = move.session();\n drop = runDropPass(\n session,\n { dx: proposed.dx, dy: proposed.dy },\n { x: ctx.pointer.worldX, y: ctx.pointer.worldY },\n );\n const opaque = drop?.pass?.reflowIds;\n const reflow = session.layout?.reflow;\n if (!reflow) return { poses: drop?.reflow, opaque };\n stepGlide(reflow, gliding, drop?.reflow ?? new Map());\n return { opaque };\n },\n\n onEnd(_ctx, end): Op[] | null | void {\n noteReleased();\n if (end.answered) return;\n const session = move.session();\n const { delta } = move.frame();\n // No-op if no movement (sub-threshold drag or zero delta).\n if (delta.dx === 0 && delta.dy === 0) return;\n // A drop or a release that claims the selection and writes nothing\n // commits nothing: the translate must not run in its place.\n const orAbort = (ops: Op[]): Op[] | null => (ops.length > 0 ? ops : null);\n // Layout drop commit — takes precedence over reparent-on-drop when a\n // layout container accepted the drag this gesture. One placement per\n // dragged child, replayed in the order the preview resolved them.\n // TODO: geometryProjection for drop-reflow — left pose-only because the\n // reflow distributes per-child poses with no single global delta; not\n // exercised by the geometry contract gate.\n if (drop?.pass) return orAbort(layoutDropOps(session, drop.pass));\n const release = layoutReleaseOps(session, delta, drop?.dropCenter ?? null);\n return release === undefined ? undefined : orAbort(release);\n },\n\n onCancel: noteReleased,\n\n onSettled(): void {\n const session = move.session();\n const reflow = session.layout?.reflow;\n // After the commit: each glide settles onto the pose the document now\n // holds, or back home on a cancel — the dragged ids from where they\n // were let go.\n if (reflow) {\n for (const id of gliding) reflow.settle(id as string);\n landReleased(session, reflow, released ?? new Map());\n }\n gliding.clear();\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;AAmBA,SAAgB,WAAW,MAA0C;CAEnE,IAAI,OAAwB;CAC5B,MAAM,0BAAU,IAAI,IAAY;CAChC,IAAI,WAAyC;CAE7C,MAAM,qBAA2B;EAC/B,MAAM,UAAU,KAAK,QAAQ;EAC7B,IAAI,QAAQ,QAAQ,QAAQ,WAAW,cAAc,SAAS,KAAK,MAAM,CAAC,CAAC,QAAQ;CACrF;CAEA,OAAO;EACL,OAAO,KAAK,UAA0C;GACpD,OAAO;GACP,MAAM,UAAU,KAAK,QAAQ;GAC7B,OAAO,YACL,SACA;IAAE,IAAI,SAAS;IAAI,IAAI,SAAS;GAAG,GACnC;IAAE,GAAG,IAAI,QAAQ;IAAQ,GAAG,IAAI,QAAQ;GAAO,CACjD;GACA,MAAM,SAAS,MAAM,MAAM;GAC3B,MAAM,SAAS,QAAQ,QAAQ;GAC/B,IAAI,CAAC,QAAQ,OAAO;IAAE,OAAO,MAAM;IAAQ;GAAO;GAClD,UAAU,QAAQ,SAAS,MAAM,0BAAU,IAAI,IAAI,CAAC;GACpD,OAAO,EAAE,OAAO;EAClB;EAEA,MAAM,MAAM,KAAyB;GACnC,aAAa;GACb,IAAI,IAAI,UAAU;GAClB,MAAM,UAAU,KAAK,QAAQ;GAC7B,MAAM,EAAE,UAAU,KAAK,MAAM;GAE7B,IAAI,MAAM,OAAO,KAAK,MAAM,OAAO,GAAG;GAGtC,MAAM,WAAW,QAA4B,IAAI,SAAS,IAAI,MAAM;GAOpE,IAAI,MAAM,MAAM,OAAO,QAAQ,cAAc,SAAS,KAAK,IAAI,CAAC;GAChE,MAAM,UAAU,iBAAiB,SAAS,OAAO,MAAM,cAAc,IAAI;GACzE,OAAO,YAAY,SAAY,SAAY,QAAQ,OAAO;EAC5D;EAEA,UAAU;EAEV,YAAkB;GAChB,MAAM,UAAU,KAAK,QAAQ;GAC7B,MAAM,SAAS,QAAQ,QAAQ;GAI/B,IAAI,QAAQ;IACV,KAAK,MAAM,MAAM,SAAS,OAAO,OAAO,EAAY;IACpD,aAAa,SAAS,QAAQ,4BAAY,IAAI,IAAI,CAAC;GACrD;GACA,QAAQ,MAAM;EAChB;CACF;AACF"}
@@ -1,5 +1,5 @@
1
- import { createReparentOp } from "../../../../core/ops/reparent.js";
2
1
  import { createTransformOp } from "../../../../core/ops/transform.js";
2
+ import { createReparentOp } from "../../../../core/ops/reparent.js";
3
3
  import { getScratch, scratchKey, setScratch } from "@weasel-js/routing";
4
4
 
5
5
  //#region src/interactions/actions/move/behaviors/snapToContainer.ts
@@ -1,11 +1,11 @@
1
1
  import { toPlane } from "../../../core/viewport/parallax.js";
2
2
  import { composeWorldPose, composesFrames, frameAtOrAbove } from "../../../core/scene/composeFrame.js";
3
3
  import { effectivePose } from "../../../core/scene/effectivePose.js";
4
+ import { scenePoseAdapter } from "../../../core/scene/scenePoseAdapter.js";
4
5
  import { scenePoseFrame } from "../poseFrame.js";
5
6
  import { poseDescriptorOf } from "../poseDescriptorDep.js";
6
7
  import { invertPlane, planeOf } from "../planeInput.js";
7
8
  import { translateTargets } from "../selectionSubtree.js";
8
- import { scenePoseAdapter } from "../../../core/scene/scenePoseAdapter.js";
9
9
  import { catchGliding } from "./layout/glide.js";
10
10
  import { pointerStateOf } from "../pointerState.js";
11
11
  import { sceneGestureFrames } from "../gestureFrames.js";